I have a RecyclerView in which I add elements and can click them to play a sound. If I create all the MediaPlayer methods inside the Adapter class everything will be properly released and only one audio will be played at a time.
//this works (code in the adapter class)
private MediaPlayer mMediaPlayer;
//release if not playing
public void releaseMediaPlayer() {
// if no sound is playing
if (mMediaPlayer != null) {
Log.d("rEEEEEEEEEEEEEEEEEEE", "releaseMediaPlayer: ");
mMediaPlayer.release();
mMediaPlayer = null;
}
}
//release media player on sound finish
public MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseMediaPlayer();
}
};
// on click listener code
releaseMediaPlayer();
mMediaPlayer = MediaPlayer.create(context, word.getmAudioResourceId());
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(mCompletionListener);
However if I use a separate class, whenever i call the the release method it doesn't release at the beginning so multiple sounds are being played at once. It releases normally onCompletion
public class MediaPlay {
private MediaPlayer mMediaPlayer;
public void setmMediaPlayer(MediaPlayer mMediaPlayer) {
this.mMediaPlayer = mMediaPlayer;
}
public MediaPlayer getmMediaPlayer() {
return mMediaPlayer;
}
//release if not playing
public void releaseMediaPlayer() {
// if no sound is playing
if (mMediaPlayer != null) {
Log.d("rEEEEEEEEEEEEEEEEEEEEEEEEEEE", "releaseMediaPlayer: ");
mMediaPlayer.release();
mMediaPlayer = null;
}
}
//release media player on sound finish
public MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseMediaPlayer();
}
};
}
onclicklistener when using class
final MediaPlay m = new MediaPlay();
m.releaseMediaPlayer();
m.setmMediaPlayer(MediaPlayer.create(context, word.getmAudioResourceId()));
m.getmMediaPlayer().start();
m.getmMediaPlayer().setOnCompletionListener(m.mCompletionListener);
I have tried creating the MediaPlay object outside the clickListener but with no result. I am basically trying to create a separate class so i can call it from my ACtivities so I can stop the sound int the onStop method. Any input will be much appreciated.
edit 1 entire viewholder with click listener
MediaPlay m;
public ViewHolder(@NonNull View itemView) {
super(itemView);
//play specific sound for each list item
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("ViewHolder: ", String.valueOf(getAdapterPosition()));
Word word = Words.get(getAdapterPosition());
if (word.hasAudio()) {
/*releaseMediaPlayer(); // stop multiple playbacks at once
mMediaPlayer = MediaPlayer.create(context, word.getmAudioResourceId());
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(mCompletionListener); //cleanup*/
if (m != null)
m.releaseMediaPlayer();
m = new MediaPlay();
//m.releaseMediaPlayer(); //TODO still plays duplicate sounds, release method not working when called like this
m.setmMediaPlayer(MediaPlayer.create(context, word.getmAudioResourceId()));
m.getmMediaPlayer().start();
m.getmMediaPlayer().setOnCompletionListener(m.mCompletionListener);
}
}
});
name = itemView.findViewById(R.id.nameT);
type = itemView.findViewById(R.id.typeT);
img = itemView.findViewById(R.id.imgV);
}
I've modified your source code with using a callback.
Please look carefully at the MyViewHolder class and onCreateViewHolder method of MyAdapter :).
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context mContext;
private String[] mDataSet;
private MediaPlayer mMediaPlayer;
public static class MyViewHolder extends RecyclerView.ViewHolder {
private TextView mTextView;
private OnMediaPlayRequestedListener mOnMediaPlayRequestedListener;
public MyViewHolder(TextView v, OnMediaPlayRequestedListener listener) {
super(v);
mTextView = v;
mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnMediaPlayRequestedListener != null) {
mOnMediaPlayRequestedListener.onMediaPlayRequested(R.raw.{resource name});
}
}
});
mOnMediaPlayRequestedListener = listener;
}
private interface OnMediaPlayRequestedListener {
void onMediaPlayRequested(int resourceId);
}
}
public MyAdapter(Context context, String[] myDataset) {
mContext = context;
mDataSet = myDataset;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
TextView view =
(TextView) LayoutInflater.from(parent.getContext()).inflate(R.layout.my_text_view, parent, false);
MyViewHolder holder = new MyViewHolder(
view,
new MyViewHolder.OnMediaPlayRequestedListener() {
@Override
public void onMediaPlayRequested(int resourceId) {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
}
mMediaPlayer = MediaPlayer.create(mContext, resourceId);
mMediaPlayer.start();
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
}
});
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder viewHolder, int position) {
viewHolder.mTextView.setText(mDataSet[position]);
}
@Override
public int getItemCount() {
return mDataSet.length;
}
}