RecyclerView Items Duplicating When Search Filtering But Only When Using Object ArrayList Instead Of String ArrayList

Viewed 40

I have an empty RecyclerView which populates with different Strings as I enter the characters in the SearchView. When I use a String ArrayList to pass it on the setItems method of the Adapter the application works as intended but I wish to do it with an object ArrayList instead so I can choose on the onBindViewHolder method which data I want to print on the RecyclerView by using the objects getters methods but the RecyclerView duplicates the items only when entering the first charcters. I´m using the same logic as when using a String ArrayList but I can´t manage to make it work properly. Any help would be much appreciated, I´m kinda desperated now as I don´t understand why it repeats the items when in the end the setText() methods uses Strings anyway...

This are the Adapter and the SearchActivity when using String ArrayList:

public class SearchViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;
    ArrayList<String> list = new ArrayList<>();

    public SearchViewAdapter(Context ctx) {
        this.context = ctx;
    }

    public void setItems(ArrayList<String> queryList) {
        this.list.addAll(queryList);
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.search_view_item, parent, false);
        return new SearchViewAdapterViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {

        SearchViewAdapterViewHolder searchViewAlbumHolder = (SearchViewAdapterViewHolder) holder;
        String string = list.get(position);

        searchViewAlbumHolder.queryText.setText(string);

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bundle bundle = new Bundle();
            }
        });
    }

    @Override
    public int getItemCount() {
        return list.size();
    }
}

SearchActivity:

public class SearchActivity extends AppCompatActivity implements Filterable {

    ActivitySearchBinding binding;
    SearchView searchView;
    SearchViewAdapter searchViewAdapter;
    RecyclerView recyclerView;
    ArrayList<String> fileredList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivitySearchBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);

        getSupportActionBar().hide(); //escondemos la action bar

        searchView = binding.searhViewID;
        searchView.setIconified(false); //desiconificamos la lupa para poder hacer focus en el searchview y poder abrir el teclado automáticamente al iniciar la activity
        searchView.requestFocus();
        searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); //para cambiar la lupa del teclado por un tick

        recyclerView = binding.searchRecyclerViewID;
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext(), RecyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(manager);
        searchViewAdapter = new SearchViewAdapter(getApplicationContext());
        recyclerView.setAdapter(searchViewAdapter);
    }

    @Override
    protected void onStart() {
        super.onStart();

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String charSequence) {
                getFilter().filter(charSequence);
                return false;
            }
        });
    }

    @Override
    public Filter getFilter() {
        return filtrado; //devuelve el objeto filter que creamos abajo
    }

    private Filter filtrado = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {

            fileredList = new ArrayList<>();

            if (charSequence == null || charSequence.length() == 0) {
                fileredList.clear(); //si no existe ningún patrón limpiamos y vaciamos la lista
            } else {
                String filterPattern = charSequence.toString().toLowerCase().trim();
                DatabaseReference dbr = FirebaseDatabase.getInstance().getReference();

                dbr.child("artists").addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) {

                        for (DataSnapshot data : snapshot.getChildren()) {
                            Artist artist = data.getValue(Artist.class);

                            if (artist.getName().toLowerCase().contains(filterPattern)) {
                                fileredList.add(artist.getName());
                            } else {
                                ArrayList<Album> albums = artist.getAlbums();
                                for (Album album : albums) {
                                    if (album.getAlbumTitle().toLowerCase().contains(filterPattern) || album.getYear().toLowerCase().contains(filterPattern) || album.getGenre().toLowerCase().contains(filterPattern)) {
                                        fileredList.add(album.getAlbumTitle() + " " + artist.getName());
                                    } else {
                                        ArrayList<Song> songs = album.getSongs();
                                        for (Song song : songs) {
                                            if (song.getSongTitle().toLowerCase().contains(filterPattern)) {
                                                fileredList.add(song.getSongTitle() + " " + artist.getName());
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        searchViewAdapter.setItems(fileredList);
                        searchViewAdapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError error) {

                    }
                });
            }
            FilterResults filterResults = new FilterResults();
            filterResults.values = fileredList;

            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            searchViewAdapter.list.clear(); //limpiamos la lista actual
            searchViewAdapter.list.addAll((ArrayList) filterResults.values);
            searchViewAdapter.notifyDataSetChanged(); //notificamos los cambios realizados
        }
    };
}

And these are the Adapter and the SearchActivity when using Object "Artist" ArrayList:

public class SearchViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;
    ArrayList<Artist> list = new ArrayList<>();
    int queryCombination;
    int albumPosition;
    int songPosition;

    public SearchViewAdapter(Context ctx) {
        this.context = ctx;
    }

    public void setItems(ArrayList<Artist> queryList, int queryCombination, int albumPosition, int songPosition) {
        this.list.addAll(queryList);
        this.queryCombination = queryCombination;
        this.albumPosition = albumPosition;
        this.songPosition = songPosition;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.search_view_item, parent, false);
        return new SearchViewAdapterViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {

        SearchViewAdapterViewHolder searchViewAlbumHolder = (SearchViewAdapterViewHolder) holder;
        Artist artist = list.get(position);

        switch (queryCombination) {
            case 1: {
                searchViewAlbumHolder.queryText.setText(artist.getName());
                break;
            }
            case 2: {
                searchViewAlbumHolder.queryText.setText(artist.getAlbums().get(albumPosition).getAlbumTitle() + " " + artist.getName());
                break;
            }
            case 3: {
                searchViewAlbumHolder.queryText.setText(artist.getAlbums().get(albumPosition).getSongs().get(songPosition).getSongTitle() + " " + artist.getName());
            }
        }

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bundle bundle = new Bundle();
                bundle.putSerializable("artist", artist);
                bundle.putInt("queryCombination", queryCombination);
                Intent intent = new Intent(context, prueba.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// addFlags para que no me de error al pasar a la nueva activity
                intent.putExtras(bundle);
                context.startActivity(intent);
            }
        });
    }

    @Override
    public int getItemCount() {
        return list.size();
    }
}

SearchActivity:

public class SearchActivity extends AppCompatActivity implements Filterable {

    ActivitySearchBinding binding;
    SearchView searchView;
    SearchViewAdapter searchViewAdapter;
    RecyclerView recyclerView;
    ArrayList<Artist> fileredList;
    int queryCombination;
    int albumPosition;
    int songPosition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivitySearchBinding.inflate(getLayoutInflater());
        View view = binding.getRoot();
        setContentView(view);

        getSupportActionBar().hide(); //escondemos la action bar

        searchView = binding.searhViewID;
        searchView.setIconified(false); //desiconificamos la lupa para poder hacer focus en el searchview y poder abrir el teclado automáticamente al iniciar la activity
        searchView.requestFocus();
        searchView.setImeOptions(EditorInfo.IME_ACTION_DONE); //para cambiar la lupa del teclado por un tick

        recyclerView = binding.searchRecyclerViewID;
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager manager = new LinearLayoutManager(getApplicationContext(), RecyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(manager);
        searchViewAdapter = new SearchViewAdapter(getApplicationContext());
        recyclerView.setAdapter(searchViewAdapter);
    }

    @Override
    protected void onStart() {
        super.onStart();

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String charSequence) {
                getFilter().filter(charSequence);
                return false;
            }
        });
    }

    @Override
    public Filter getFilter() {
        return filtrado; //devuelve el objeto filter que creamos abajo
    }

    private Filter filtrado = new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {


            if (charSequence == null || charSequence.length() == 0) {
                fileredList.clear(); //si no existe ningún patrón limpiamos y vaciamos la lista
            } else {
                String filterPattern = charSequence.toString().toLowerCase().trim();
                DatabaseReference dbr = FirebaseDatabase.getInstance().getReference();

                fileredList = new ArrayList<>();

                dbr.child("artists").addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot snapshot) {

                        for (DataSnapshot data : snapshot.getChildren()) {
                            Artist artist = data.getValue(Artist.class);
                            if (artist.getName().toLowerCase().contains(filterPattern)) {
                                queryCombination = 1;
                                fileredList.add(artist);
                            } else {
                                ArrayList<Album> albums = artist.getAlbums();
                                for (Album album : albums) {
                                    if (album.getAlbumTitle().toLowerCase().contains(filterPattern)) {
                                        albumPosition = albums.indexOf(album);
                                        queryCombination = 2;
                                        fileredList.add(artist);
                                    } else {
                                        ArrayList<Song> songs = album.getSongs();
                                        for (Song song : songs) {
                                            if (song.getSongTitle().toLowerCase().contains(filterPattern)) {
                                                albumPosition = albums.indexOf(album);
                                                songPosition = songs.indexOf(song);
                                                queryCombination = 3;
                                                fileredList.add(artist);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        searchViewAdapter.setItems(fileredList, queryCombination, albumPosition, songPosition);
                        searchViewAdapter.notifyDataSetChanged();
                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError error) {

                    }
                });
            }
            FilterResults filterResults = new FilterResults();
            filterResults.values = fileredList;

            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            searchViewAdapter.list.clear(); //limpiamos la lista actual
            searchViewAdapter.list.addAll((ArrayList) filterResults.values);
            searchViewAdapter.notifyDataSetChanged(); //notificamos los cambios realizados
        }
    };
}
0 Answers
Related