Search code examples
androidaudioandroid-mediaplayer

MediaPlayer pause called in state 8


I am trying to implement a RecyclerView with audio messages and playing those audio files. Previously I was stuck on a problem when I was changing play and pause image on ImageButton, so I found this solution and changed my code accordingly. But now I am facing another issue. Whenever I play the audio , the image changes to pause and when I click this button again, it gives me an error: pause called in state 8. I know what is causing the problem, but cannot figure out the solution. Here is my onBindViewHolder :

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            ((MyChatMediaViewHolder) holder).bindData(mChats.get(position), position);
}

Here is my MyChatMediaViewHolder class :

private class MyChatMediaViewHolder extends RecyclerView.ViewHolder {
    private TextView txtUserAlphabet, timer;
    private ImageView play;
    private SeekBar seekBar;
    ProgressBar progressBar;
    RelativeLayout media_chat;
    Chat chat = null;

    public MyChatMediaViewHolder(View itemView) {
        super(itemView);
        play = (ImageView) itemView.findViewById(R.id.play);
        seekBar = (SeekBar) itemView.findViewById(R.id.seekbar);
        txtUserAlphabet = (TextView) itemView.findViewById(R.id.text_view_user_alphabet);
        progressBar = (ProgressBar) itemView.findViewById(R.id.progressUpdate);
        media_chat = (RelativeLayout) itemView.findViewById(R.id.chat_media);
        timer = (TextView) itemView.findViewById(R.id.timer);
        Log.e("TAG111", "bindData: ");

        play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                isPlay = !isPlay;
                //Handling for background selection state changed
                int previousSelectState=mSelectedItemPosition;
                mSelectedItemPosition = getAdapterPosition();
                //notify previous selected item
                notifyItemChanged(previousSelectState);
                //notify new selected Item
                notifyItemChanged(mSelectedItemPosition);
            }
        });
    }

    public void bindData(Chat chat, int currentPosition) {
        this.chat = chat;
        MediaPlayer mediaPlayer = new MediaPlayer();
        MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();

        try {
            mediaPlayer.setDataSource(chat.mediaUrlLocal);
            metaRetriever.setDataSource(chat.mediaUrlLocal);
            mediaPlayer.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }

        String duration =
                metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        long dur = Long.parseLong(duration);
        String seconds = String.valueOf((dur % 60000) / 1000);

        String minutes = String.valueOf(dur / 60000);
        String out = minutes + ":" + seconds;

        timer.setText(out);

        if(currentPosition == mSelectedItemPosition) {
            Log.e("pause", "bindData: " + mediaPlayer.isPlaying());
            if(isPlay) {
                mediaPlayer.start();
                play.setImageResource(android.R.drawable.ic_media_pause);
            } else {
                mediaPlayer.pause();
                play.setImageResource(android.R.drawable.ic_media_play);
            }

        } else {
            play.setImageResource(android.R.drawable.ic_media_play);
        }
    }
}

The problem here I think is : new MediaPlayer instance gets created every time play button is clicked, so when I try to pause , a new media player is again created which was never started.

So the question is : Where should I create the new MediaPlayer instance?


Solution

  • First of all your RecyclerView.Adapter's purpose is to inflate your view, you shouldn't write your business logic here.

    Second you should use only one instance of media player. You should initialize your media player inside your Activity or Fragment.

    Create an interface implement in your Activity or Fragment and pass its reference to your adapter. Whenever you want to play audio you will use your interface to delegate your audio file path or stream to Activity or Fragment, reset or release your media player and play your audio.