When I opened the searched item, it is opening the first item of ListView not the searched one. Even if search and find the items successfuly.
I configure the adapter with "implements Filterable" and enable Listview with ".setTextFilterEnabled(true)", but doesn´t work.
I saw that I must implement "public Filter getFilter()" but I have no idea how can I do that.
When I type some words in EditText, like "cel" or "12" the filter goes in action, but the result is always the same: The first two items in Listview, no matter what is into the Listview (the content of listview is random).
Below a snippet of my Activity:
public class MusicActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
private boolean checkPermission = false;
ProgressDialog progressDialog;
ListView listView;
List<String> songsNameList;
List<String> songsUrlList;
List<String> songsArtistList;
List<String> songsDurationList;
ListAdapter adapter;
JcPlayerView jcPlayerView;
List<JcAudio> jcAudios;
List<String> thumbnail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
progressDialog = new ProgressDialog(this);
progressDialog.show();
progressDialog.setMessage("Please Wait...");
listView = findViewById(R.id.songsList);
songsNameList = new ArrayList<>();
songsUrlList = new ArrayList<>();
songsArtistList = new ArrayList<>();
songsDurationList = new ArrayList<>();
jcAudios = new ArrayList<>();
thumbnail = new ArrayList<>();
jcPlayerView = findViewById(R.id.jcplayer);
retrieveSongs();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
jcPlayerView.playAudio(jcAudios.get(i));
jcPlayerView.setVisibility(View.VISIBLE);
jcPlayerView.createNotification();
adapter.notifyDataSetChanged();
}
});
}
// RETRIEVING THE SONGS FROM THE SERVER
public void retrieveSongs() {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Songs");
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
Song song = ds.getValue(Song.class);
songsNameList.add(song.getSongName());
songsUrlList.add(song.getSongUrl());
songsArtistList.add(song.getSongArtist());
songsDurationList.add(song.getSongDuration());
thumbnail.add(song.getImageUrl());
jcAudios.add(JcAudio.createFromURL(song.getSongName(), song.getSongUrl()));
}
adapter = new ListAdapter(getApplicationContext(), songsNameList, thumbnail, songsArtistList, songsDurationList);
jcPlayerView.initPlaylist(jcAudios, null);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
progressDialog.dismiss();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(MusicActivity.this, "FAILED!", Toast.LENGTH_SHORT).show();
}
});
}
/*@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.app_menu,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.searchmenu:
startActivity(new Intent(MusicActivity.this,Search.class));
break;
case R.id.requestmenu:
startActivity(new Intent(MusicActivity.this,UploadSongActivity.class));
break;
case R.id.sharemenu:
break;
}
return true;
}*/
// Filter Class
// METHOD TO HANDEL RUNTIME PERMISSIONS
private boolean validatePermissions(){
Dexter.withContext(getApplicationContext())
.withPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new PermissionListener() {
@Override
public void onPermissionGranted(PermissionGrantedResponse permissionGrantedResponse) {
checkPermission = true;
}
@Override
public void onPermissionDenied(PermissionDeniedResponse permissionDeniedResponse) {
checkPermission = false;
}
@Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permissionRequest, PermissionToken permissionToken) {
permissionToken.continuePermissionRequest();
}
}).check();
return checkPermission;
}
@Override
public boolean onQueryTextSubmit(String query) {
Toast.makeText(this, "Query Inserted", Toast.LENGTH_SHORT).show();
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
if(TextUtils.isEmpty(newText)){
adapter.filter("");
listView.clearTextFilter();
}else{
String texto = newText;
adapter.filter(newText);
}
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.searchmenu, menu);
MenuItem searchItem = menu.findItem(R.id.search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setQueryHint("Search Catholic songs");
searchView.setOnQueryTextListener(this);
searchView.setIconified(false);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.search) {
return true;
}
else if(id == R.id.Rate){
/*if (mInterstitialAd.isLoaded()) {
mInterstitialAd.show();
} else {
//log.d("TAG", "The intersitial wasn't loaded yet.");
}*/
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getString(R.string.packegname)));
startActivity(intent);
}
else if (id ==R.id.sharemenu){
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT,
"Hey ! check out this music service that gives you access to Hundreds of catholic songs. through Catholic app at: https://play.google.com/store/apps/details?id=" + BuildConfig.APPLICATION_ID);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
else if(id == R.id.uploadItem){
if (validatePermissions()){
Intent intent = new Intent(this,UploadSongActivity.class);
startActivity(intent);
}
}
return super.onOptionsItemSelected(item);
}
and below my CustomAdapter:
public class ListAdapter extends BaseAdapter {
List<String> songNames;
List<String> thumbnails;
List<String> songArtist;
List<String> songDuration;
Context context;
private List<String> copyList;
private int searchedItem = -1;
private ArrayList<Song> arraylist;
public ListAdapter(Context context, List<String> songNames, List<String> thumbnails, List<String> songArtist, List<String> songDuration) {
this.context = context;
this.songNames = songNames;
this.thumbnails = thumbnails;
this.songArtist = songArtist;
this.songDuration = songDuration;
copyList = new ArrayList<String>();
copyList.addAll(songNames);
}
@Override
public int getCount() {
return songNames.size();
}
@Override
public Object getItem(int i) {
return songNames.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@SuppressLint({"InflateParams", "ViewHolder"})
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final ViewHolder viewHolder;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.songs_list_layout, null);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) view.getTag();
}
Transformation transformation = new RoundedTransformationBuilder()
.cornerRadiusDp(15)
.build();
Picasso.get().load(thumbnails.get(i)).transform(transformation).into(viewHolder.thumbnail);
viewHolder.songName.setText(songNames.get(i));
viewHolder.artistName.setText(songArtist.get(i));
viewHolder.songDuration.setText(songDuration.get(i));
return view;
}
public void filter(String queryText)
{
songNames.clear();
if(queryText.isEmpty())
{
songNames.addAll(copyList);
}
else
{
for(String name: copyList)
{
if(name.toLowerCase().contains(queryText.toLowerCase()))
{
songNames.add(name);
}
}
}
notifyDataSetChanged();
}
private static class ViewHolder{
TextView songName;
TextView artistName;
TextView songDuration;
ImageView thumbnail;
CardView cardView;
ImageView currentlyPlaying;
ViewHolder(View view){
songName = view.findViewById(R.id.songName);
thumbnail = view.findViewById(R.id.songThumbnail);
artistName = view.findViewById(R.id.artistName);
songDuration = view.findViewById(R.id.songDuration);
cardView = view.findViewById(R.id.cardView);
currentlyPlaying = view.findViewById(R.id.currentlyPlaying);
}
}
What is missing?
I improved your adapter, didn't test it but it should work... I think it's easier to forward the Song list than the lists for each field separately... You have the original list for filtering and filteredList for adapter views...
EDITED: You have to implement Filterable, sorry i didnt see this...
public class ListAdapter extends BaseAdapter implements Filterable {
private final Context context;
private final List<Song> songlist;
private final List<Song> filteredList;
public ListAdapter(Context context, List<Song> songlist) {
this.context = context;
this.songlist = songlist;
filteredList = new ArrayList<>();
filteredList.addAll(songlist);
}
@Override
public int getCount() {
return filteredList.size();
}
@Override
public Object getItem(int i) {
return filteredList.get(i); // return Song item
}
@Override
public long getItemId(int i) {
return i; //TODO change this to return song id
}
@SuppressLint({"InflateParams", "ViewHolder"})
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final ViewHolder viewHolder;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.songs_list_layout, null);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) view.getTag();
}
Transformation transformation = new RoundedTransformationBuilder()
.cornerRadiusDp(15)
.build();
Song song = filteredList.get(i);
Picasso.get().load(song.getImageUrl()).transform(transformation).into(viewHolder.thumbnail);
viewHolder.songName.setText(song.getSongName());
viewHolder.artistName.setText(song.getSongArtist());
viewHolder.songDuration.setText(song.getSongDuration());
return view;
}
@Override
public Filter getFilter() {
return new Filter() {
@Override
protected FilterResults performFiltering (CharSequence constraint) {
FilterResults results = new FilterResults();
if (songlist != null && constraint != null) {
filteredList.clear();
List<Song> newValues = new ArrayList<>();
for (Song song: songlist) {
if(constraint.length() == 0) {
newValues.add(song); //TODO change this if you want empty list
}else{
if(song.getSongName.toLowerCase().contains(constraint.toString().toLowerCase())) {
newValues.add(song);
}
}
}
filteredList.addAll(newValues);
//filteredList = newValues;
results.count = newValues.size();
}
return results;
}
@Override
protected void publishResults (CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
}
private static class ViewHolder{
TextView songName;
TextView artistName;
TextView songDuration;
ImageView thumbnail;
CardView cardView;
ImageView currentlyPlaying;
ViewHolder(View view){
songName = view.findViewById(R.id.songName);
thumbnail = view.findViewById(R.id.songThumbnail);
artistName = view.findViewById(R.id.artistName);
songDuration = view.findViewById(R.id.songDuration);
cardView = view.findViewById(R.id.cardView);
currentlyPlaying = view.findViewById(R.id.currentlyPlaying);
}
}
}
and
public void retrieveSongs() {
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Songs");
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<Song> songsList = new ArrayList<>();
for (DataSnapshot ds : snapshot.getChildren()) {
Song song = ds.getValue(Song.class);
songsList.add(song);
jcAudios.add(JcAudio.createFromURL(song.getSongName(), song.getSongUrl()));
}
adapter = new ListAdapter(getApplicationContext(), songsList);
jcPlayerView.initPlaylist(jcAudios, null);
listView.setAdapter(adapter);
adapter.notifyDataSetChanged();
progressDialog.dismiss();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Toast.makeText(MusicActivity.this, "FAILED!", Toast.LENGTH_SHORT).show();
}
});
}
Also its better to create one instance of adapter and swapData in retrieveSongs...
EDITED: Try something like this
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Song song = (Song)adapter.getItem(i)
jcPlayerView.playAudio(JcAudio.createFromURL(song.getSongName(), song.getSongUrl()));
jcPlayerView.setVisibility(View.VISIBLE);
jcPlayerView.createNotification();
adapter.notifyDataSetChanged();
}
});