I have this RecyclerView that is a list of of instrumental beats, each item containing an Instrumental Name, Producer Name, and Audio Source that is retrieved from Firebase Storage. When you click on the play button, it triggers the OnClickListener and sets the data source to the position of the item's music link and plays the audio with OnPrepareListener. The problem I'm having is that if I click a different item's play button, it plays that audio as well, when my objective is to stop the previous audio and start the new audio. Here's my code:
public void onBindViewHolder(@NonNull final TrackHolder holder, final int position) {
holder.mInstrumentalName.setText(tracks.get(position).getInstrumentalName());
holder.mProducer.setText(tracks.get(position).getProducer());
final MediaPlayer mediaPlayer = new MediaPlayer();
holder.mPlayButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.mPlayButton.toggle();
try {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(tracks.get(position).getMusicLink());
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
if (mediaPlayer.isPlaying()) {
Log.d("is_playing", "is_playing");
mediaPlayer.stop();
try {
mediaPlayer.setDataSource(tracks.get(position).getMusicLink());
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.start();
} else {
mediaPlayer.start();
}
}
});
mediaPlayer.prepareAsync();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
Log.d("released", "released");
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
});
holder.setItemClickListener(new ItemClickListener() {
@Override
public void onItemClick(View v, int pos) {
Toast.makeText(context, Integer.toString(tracks.size()), Toast.LENGTH_SHORT).show();
}
});
}
The picture below shows the list of items, with the the yellow meaning that the music is playing, and black not playing:
Use a single global MediaPlayer rather than a player per view. Then when you click an item, stop the audio, set a new data source, and restart.
Using multiple MediaPlayers in general is a bad idea anyway, those things use a ton of memory. Your current code is pretty bad because of it. Creating a new one on every bind is a lot of wasted memory and can lead to slow scrolling.