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
}
};
}