Search code examples
androidandroid-mediaplayerandroid-recyclerviewandroid-seekbar

How to use the Audio with seekbar on Recyclview android?


I am using the lists of audio on my Recyclview and it is working correct means I am able to play the audio file on my Recyclview.

As i am using the Seekbar with my audio file on my Recyclview , the problem is generating that when i am scrolling the Recyclview the other items's of Recyclview Seekbar is changing (Seekbar i am using for the progress of the audio file play.)

What i want that other Seekbar item of Recyclview sholud not be change when i scroll the Recyclview

Please check my code for it ,Inside the onBindViewHolder for my Recyclview , i am using the following code, please check it once.

 ((MyAudioChat) holder).sbMyAudio.setTag(position);
            ((MyAudioChat) holder).imgPlayAudio.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ((MyAudioChat) holder).sbMyAudio.removeCallbacks(null);
                    ((MyAudioChat) holder).sbMyAudio.setProgress(0);
                    if (mediaPlayer == null) {
                        mediaPlayer();
                        ((MyAudioChat) holder).sbMyAudio.setMax(mediaPlayer.getDuration());
                    } else {
                        mediaPlayer.stop();
                        mediaPlayer.release();
                        mediaPlayer();
                        ((MyAudioChat) holder).sbMyAudio.setMax(mediaPlayer.getDuration());
                    }

                    ((MyAudioChat) holder).sbMyAudio.getTag();
                    ((MyAudioChat) holder).sbMyAudio.setMax(mediaPlayer.getDuration()); // Set the Maximum range of the
                    ((MyAudioChat) holder).sbMyAudio.setProgress(mediaPlayer.getCurrentPosition());// set current progress to song's
                    Runnable moveSeekBarThread = new Runnable() {
                        public void run() {
                            if (mediaPlayer.isPlaying()) {

                                int mediaPos_new = mediaPlayer.getCurrentPosition();
                                int mediaMax_new = mediaPlayer.getDuration();
                                ((MyAudioChat) holder).sbMyAudio.setMax(mediaMax_new);
                                ((MyAudioChat) holder).sbMyAudio.setProgress(mediaPos_new);
                                ((MyAudioChat) holder).sbMyAudio.postDelayed(this, 100); //Looping the thread after 0.1 second
                                ((MyAudioChat) holder).sbMyAudio.getTag();
                            }

                        }
                    };

                    ((MyAudioChat) holder).sbMyAudio.removeCallbacks(moveSeekBarThread);
                    ((MyAudioChat) holder).sbMyAudio.postDelayed(moveSeekBarThread, 100);

                }
            });

I have visited the following site on SO but did not get the relevant solution
1 .First Link
2. Second Link

Can we use the setTag() and getTag() to get rid of from this problem. I have used the setTag() on my above code. Please check it once.


Solution

  • Although, you have asked only about correct SeekBar updates, I am assuming (because you haven't shard complete source) that soon you will face following issues which are linked to the Adapter implementation:

    • How do I remove the seekBar updater, when MediaPlayer completes the playback of audio?
    • How do I release the MediaPlayer when activity is paused?
    • Anonymous View.OnClickListeners and Runnables are being allocated on every onBindViewHolder call. How do I minimize their unnecessary allocation?

    You can find complete working solution here - GitHub

    Following source tries to fix all above issues. Certain data structures/classes are assumed based on your nomenclature.

    public class MainActivity extends Activity {
    
        private MediaPlayer mediaPlayer;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
            rv.setLayoutManager(new LinearLayoutManager(this));
            AudioChat audioChats[] = new AudioChat[128];
            rv.setAdapter(new MyAdapter(Arrays.asList(audioChats)));
    
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (null != mediaPlayer) {
                mediaPlayer.release();
                mediaPlayer = null;
            }
        }
    
        private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyAudioChat> {
    
            private List<AudioChat> audioChats;
            private int currentPlayingPosition;
            private SeekBarUpdater seekBarUpdater;
    
            MyAdapter(List<AudioChat> audioChats) {
                this.audioChats = audioChats;
                this.currentPlayingPosition = -1;
                seekBarUpdater = new SeekBarUpdater();
            }
    
            @Override
            public MyAudioChat onCreateViewHolder(ViewGroup parent, int viewType) {
                return new MyAudioChat(LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false));
            }
    
            @Override
            public void onBindViewHolder(MyAudioChat holder, int position) {
                if (position == currentPlayingPosition) {
                    seekBarUpdater.playingHolder = holder;
                    holder.sbMyAudio.post(seekBarUpdater);
                } else {
                    holder.sbMyAudio.removeCallbacks(seekBarUpdater);
                    holder.sbMyAudio.setProgress(0);
                }
            }
    
            private class SeekBarUpdater implements Runnable {
                MyAudioChat playingHolder;
    
                @Override
                public void run() {
                    if (null != mediaPlayer && playingHolder.getAdapterPosition() == currentPlayingPosition) {
                        playingHolder.sbMyAudio.setMax(mediaPlayer.getDuration());
                        playingHolder.sbMyAudio.setProgress(mediaPlayer.getCurrentPosition());
                        playingHolder.sbMyAudio.postDelayed(this, 100);
                    } else {
                        playingHolder.sbMyAudio.removeCallbacks(seekBarUpdater);
                    }
                }
            }
    
            @Override
            public int getItemCount() {
                return audioChats.size();
            }
    
            class MyAudioChat extends RecyclerView.ViewHolder implements View.OnClickListener {
                SeekBar sbMyAudio;
                ImageView imgPlayAudio;
    
                MyAudioChat(View itemView) {
                    super(itemView);
                    imgPlayAudio = (ImageView) itemView.findViewById(R.id.imgPlayAudio);
                    imgPlayAudio.setOnClickListener(this);
                    sbMyAudio = (SeekBar) itemView.findViewById(R.id.sbMyAudio);
                }
    
                @Override
                public void onClick(View v) {
                    currentPlayingPosition = getAdapterPosition();
                    if (mediaPlayer != null) {
                        if (null != seekBarUpdater.playingHolder) {
                            seekBarUpdater.playingHolder.sbMyAudio.removeCallbacks(seekBarUpdater);
                            seekBarUpdater.playingHolder.sbMyAudio.setProgress(0);
                        }
                        mediaPlayer.release();
                    }
                    seekBarUpdater.playingHolder = this;
                    startMediaPlayer();
                    sbMyAudio.setMax(mediaPlayer.getDuration());
                    sbMyAudio.post(seekBarUpdater);
                }
            }
    
            private void startMediaPlayer() {
                mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.mp3);
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        seekBarUpdater.playingHolder.sbMyAudio.removeCallbacks(seekBarUpdater);
                        seekBarUpdater.playingHolder.sbMyAudio.setProgress(0);
                        mediaPlayer.release();
                        mediaPlayer = null;
                        currentPlayingPosition = -1;
                    }
                });
                mediaPlayer.start();
            }
        }
    
        private class AudioChat {
    
        }
    }