Recyclerview viewholder possible to change views at other adapter positions (not current position)?

Nicholas Muir picture Nicholas Muir · Feb 9, 2016 · Viewed 10k times · Source

I have a recyclerview with mediaplayer to play a song on each row. I only have one button for play/stop which changes symbol.

Here is my problem:

Example 1 (This works fine):

(For adapter position 1) the user hits the play symbol and music plays for that adapter position and the symbol changes to a stop symbol, they then hit the stop symbol and the music stops and the symbol changes back to a play symbol ready to start the music again.

Example 2 (This is the problem)

(For adapter position 1) the user hits the play symbol and music plays for that adapter position and the symbol changes to a stop symbol. Without hitting that button again they then hit the play symbol (adapter position 3) so now they are trying to play the song on position 1 and 3 at the same time. I have fixed both songs playing at the same time so that when the the second song is pressed the media played is reset and the source song file is changed to the new song (only one will play at a time).

The problem then becomes even though the media player is behaving as it should. The mediaplayer is controlled in the mainactivity. The play/stop button (imageview) image is changed in the the adapter viewholder and I can't work out a way to change the play/stop symbol when more than one song is clicked at the same time.

This image shows the example both song 1 and song 3 have been pressed. Now only song 3 is playing but the images are still showing as if both songs are playing simultaneously.

enter image description here

This is my view holder where I handle changing the play/stop image and send the song clicked callback:

class AddVideoAudioViewHolder extends RecyclerView.ViewHolder{

    ImageView PlayButton;
    Button AddAudioButton;
    TextView Title;
    public AddVideoAudioViewHolder(View itemView) {
        super(itemView);

        PlayButton = (ImageView) itemView.findViewById(R.id.PlayStopAudioDemo);
        PlayButton.setTag(1);
        PlayButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                int PlayStopButtonState = (int) PlayButton.getTag();

                if (PlayStopButtonState == 1) {
                    mVideoAudioCallbacks.onClick(100 + getAdapterPosition());
                    PlayButton.setImageResource(R.drawable.playstop);
                    PlayButton.setTag(2);

                } else {

                    mVideoAudioCallbacks.onClick(200 + getAdapterPosition());
                    PlayButton.setImageResource(R.drawable.playarrow);
                    PlayButton.setTag(1);
                }


            }
        });

and this is the method in the main activity where I handle the case of two songs playing:

public void PlaySong (int SongNumber, int ObjectInt){


    if (mp == null) {

        mp = new MediaPlayer();

    }else{
        mp.reset();
    }

    try {
        mp.setDataSource(this, Uri.parse("android.resource://com.example.nick.accountable/" + SongArray[SongNumber]));
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        mp.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
    mp.start();



}

So my question can I add some code in the view holder or in the main activity that can change all the other views than the current adapter position. I.e. If song number 3 is clicked to play, set the image for position 1-2 & 4-10 as not playing or is there a better way to do it.

Thanks for your help Nicholas

Answer

Much Overflow picture Much Overflow · Feb 9, 2016

In your adapter have an int variable to maintain which position is being played

int mCurrentPlayingPosition = -1; // if -1 nothing is playing

in your play button's on click listener, do this

PlayButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                int PlayStopButtonState = (int) PlayButton.getTag();

                int previousPosition = mCurrentPlayingPosition;
                if (PlayStopButtonState == 1) {

                    mCurrentPlayingPosition = getAdapterPosition();

                    mVideoAudioCallbacks.onClick(100 + getAdapterPosition());
                    PlayButton.setImageResource(R.drawable.playstop);
                    PlayButton.setTag(2);

                } else {
                    mCurrentPlayingPosition = -1; // nothing wil be played after hitting stop
                    mVideoAudioCallbacks.onClick(200 + getAdapterPosition());
                    PlayButton.setImageResource(R.drawable.playarrow);
                    PlayButton.setTag(1);
                }

                if(previousPosition != -1)
                    notifyItemChanged(previousPosition);

            }
        });

in your onBindViewHolder do the following

@Override
public void onBindViewHolder(AddVideoAudioViewHolder holder, int position) {
    if(mCurrentPlayingPosition == position ){
       // display stop icon
    } else {
       // display play icon
    }
}