Reputation: 29
I'm creating a simple app with one TextView and ImageButton view, I am using RecyclerView to display list of pairs of these so I wrote my custom adapter and view holder. But I have one problem how to release MediaPlayer when a user goes to the home screen. Because I initialize MediaPlayer inside adapter and I don't know how to trigger release if activity is being stopped. Here's my code:
Activity class:
public class NumbersActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_word_list);
List<Word> words = new ArrayList<>();
words.add(new Word("one", R.raw.number_one));
words.add(new Word("two", R.raw.number_two));
words.add(new Word("three", R.raw.number_three));
words.add(new Word("four", R.raw.number_four));
words.add(new Word("five", R.raw.number_five));
LinearLayoutManager numbersListLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
RecyclerView listView = findViewById(R.id.word_list);
listView.setLayoutManager(numbersListLayoutManager);
listView.setAdapter(new WordAdapter(this, words));
}
}
Adapter class:
public class WordAdapter extends RecyclerView.Adapter<WordAdapter.ViewHolder> {
private Context context;
private List<Word> words;
private MediaPlayer mediaPlayer;
public WordAdapter(Context context, List<Word> words) {
this.context = context;
this.words = words;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View viewItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new ViewHolder(viewItem);
}
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
stopPlaying();
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.englishTranslation.setText(this.words.get(position).getDefaultTranslation());
holder.itemView.setOnClickListener((view) -> {
stopPlaying();
mediaPlayer = MediaPlayer.create(this.context, this.words.get(position).getAudioResourceId());
mediaPlayer.setOnCompletionListener((mp) -> {
stopPlaying();
});
mediaPlayer.start();
});
}
@Override
public int getItemCount() {
return words.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView englishTranslation;
ImageButton playButton;
public ViewHolder(View wordView) {
super(wordView);
this.englishTranslation = wordView.findViewById(R.id.english_text_view);
this.playButton = wordView.findViewById(R.id.play_button);
}
}
private void stopPlaying() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
}
Should I pass MediaPlayer object to adapter and control it's state from activity class ? Or is it possible to do it from inside of adapter?
Upvotes: 1
Views: 1173
Reputation: 3097
@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
stopPlaying();
}
Here you are setting to stop your player.
It is triggered when ViewHolder
is not visible on screen
You should have your player instance inside Activity and control it by Interface callbacks (listener pattern) from adapter.
Also it is going to be much better for performance to have single media player instead of many inside VH
Callback should look like this:
interface PlayableItemCallback {
void onItemVisible(int position);
void onPlay(int position);
void onStop(int position);
}
Implement it in your activity and use it to control your MediaPlayer with passing it in to adapter. Activity code:
public class NumbersActivity extends AppCompatActivity implements PlayableItemCallback {
MediaPlayer mediaPlayer;
Adapter adapter = Adapter(this)
// .............
@Override
public void onItemVisible(int position) {
// do stuff with player
}
@Override
public void onPlay(int position) {
// do stuff with player
}
@Override
public void onStop(int position) {
// do stuff with player
}
}
Upvotes: 3
Reputation: 2912
You can stop the media player using stopPlaying
method. To make it work you have to create the instance of the adapter and when onStop()
call just call the method from the adapter and you are done!!!
Create the instance of the adapter
private WordAdapter mWordAdapter;
mWordAdapter = new WordAdapter(this, words)
listView.setAdapter(mWordAdapter)
override the onStop method in your activity
@Override
protected void onStop() {
super.onStop();
if(mWordAdapter!=null){
mWordAdapter.stopPlaying()
}
}
Make stopPlaying
method public so you can access it via object.
public void stopPlaying() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
Upvotes: 1