In my app i have recyclerview items, and each item play sound when i click it. Problem is that when i click few items, they all play sounds in the same time until they finish. Lets say i click 10 items, all 10 play sounds in the same time and after some time app get crashed and i get this error: E/MediaPlayer: error (1, -19). I avoid app crashing by implementing automatic release with this code:
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mediaPlayer.release(); } });
But that's not what i want, it is annoying to hear few sounds in the same time. What i want is to stop previous sound when i click new one, i try to implent mediaplayer stop and release, but without success.
This is the app in google play so you can check by yourself: https://play.google.com/store/apps/details?id=org.pero.androidd.animalSoundsQuiz
Here is my Adapter code where i play sounds. In this code there is part MediaPlayer.OnCompletionListener() where i release sound after sound finish to aviod E/MediaPlayer: error (1, -19) error, but that is not what i want in my app. I want to stop previous sound after i click new one.
import android.content.Context; import android.media.MediaPlayer; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.pero.androidd.animalsoundsforchildren.R; import java.util.List; public class ZivotinjeAdapter extends RecyclerView.Adapter<ZivotinjeAdapter.ViewHolder> { private List<Zivotinje> mZivotinje; @Override public ZivotinjeAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(context); // Inflate the custom layout View contactView = inflater.inflate(R.layout.item_zivotinje, parent, false); // Return a new holder instance ViewHolder viewHolder = new ViewHolder(contactView); return viewHolder; } @Override public void onBindViewHolder(ZivotinjeAdapter.ViewHolder viewHolder, int position) { Zivotinje zivotinjeIme = mZivotinje.get(position); // Set item views based on the data model TextView textView = viewHolder.nameTextView; textView.setText(zivotinjeIme.getmAnimal_name()); //THIS IS WHERE I HANDALE IMAGE VIEW. Using glide for images //Dohvacamo context svakog views ImageView slika_source = viewHolder.imageView; Glide.with(slika_source.getContext()) .load((Integer) zivotinjeIme.getmAnimal_slika()) .into(slika_source); viewHolder.setItem(mZivotinje.get(position)); } @Override public int getItemCount() { return mZivotinje.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView imageView; public TextView nameTextView; private Zivotinje mItem; public void setItem(Zivotinje item) { this.mItem = item; } public ViewHolder(final View itemView) { super(itemView); nameTextView = (TextView) itemView.findViewById(R.id.zivotinjaIme_id); imageView = (ImageView) itemView.findViewById(R.id.slika_id); //Handdaling clicks itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final MediaPlayer mediaPlayer = MediaPlayer.create(v.getContext(), mItem.getmSound()); mediaPlayer.start(); //releace media player after sound finish // BUT I DO NOT WANT TIS, I WANT TO STOP PREVIOUS SOUND WHEN I CLICK NEW ONE mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mediaPlayer.release(); } }); } }); } } public ZivotinjeAdapter(List<Zivotinje> animals) { mZivotinje = animals; } }
EDIT EDIT EDIT EDIT EDIT EDIT:
I find solution, i do not know is this the smartest way to do it but it works for me fine:
What i done is that i made static media player variable and this way i can access to media player from ViewHolder and stop previous sound when i click new one. Hope it helps.
here is the whole code:
public class ZivotinjeAdapter extends RecyclerView.Adapter<ZivotinjeAdapter.ViewHolder> { private static MediaPlayer mediaPlayer; //THIS IS THE CHANGE I DONE @Override public ZivotinjeAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { Context context = parent.getContext(); LayoutInflater inflater = LayoutInflater.from(context); // Inflate the custom layout View contactView = inflater.inflate(R.layout.item_zivotinje, parent, false); // Return a new holder instance ViewHolder viewHolder = new ViewHolder(contactView); return viewHolder; } @Override public void onBindViewHolder(ZivotinjeAdapter.ViewHolder viewHolder, int position) { Zivotinje zivotinjeIme = mZivotinje.get(position); // Set item views based on the data model TextView textView = viewHolder.nameTextView; textView.setText(zivotinjeIme.getmAnimal_name()); //THIS IS WHERE I HANDALE IMAGE VIEW. Using glide for images ImageView slika_source = viewHolder.imageView; Glide.with(slika_source.getContext()) .load((Integer) zivotinjeIme.getmAnimal_slika()) .into(slika_source); viewHolder.setItem(mZivotinje.get(position)); } @Override public int getItemCount() { return mZivotinje.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public ImageView imageView; public TextView nameTextView; private Zivotinje mItem; public void setItem(Zivotinje item) { this.mItem = item; } public ViewHolder(final View itemView) { super(itemView); nameTextView = (TextView) itemView.findViewById(R.id.zivotinjaIme_id); imageView = (ImageView) itemView.findViewById(R.id.slika_id); //handaling clicks itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); mediaPlayer.reset(); mediaPlayer.release(); mediaPlayer = null; } mediaPlayer = MediaPlayer.create(v.getContext(), mItem.getmSound()); mediaPlayer.start(); } }); } } private List<Zivotinje> mZivotinje; public ZivotinjeAdapter(List<Zivotinje> animals) { mZivotinje = animals; } }