Search code examples
androidfirebaselistviewsearchviewbaseadapter

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


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?


Solution

  • 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();
            }
        });