RecyclerView 在活动(activity)的 onStop 被触发时释放 MediaPlayer。

huangapple go评论89阅读模式
英文:

RecyclerView release MediaPlayer when activity onStop is triggered

问题

以下是您提供的内容的翻译部分:

活动类:

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));
    }
}

适配器类:

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;
            }
        }
    }

您是否应该将 MediaPlayer 对象传递给适配器,并从活动类中控制它的状态?还是可以在适配器内部执行此操作呢?

英文:

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&lt;Word&gt; words = new ArrayList&lt;&gt;();
words.add(new Word(&quot;one&quot;, R.raw.number_one));
words.add(new Word(&quot;two&quot;, R.raw.number_two));
words.add(new Word(&quot;three&quot;, R.raw.number_three));
words.add(new Word(&quot;four&quot;, R.raw.number_four));
words.add(new Word(&quot;five&quot;, 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&lt;WordAdapter.ViewHolder&gt; {
private Context context;
private List&lt;Word&gt; words;
private MediaPlayer mediaPlayer;
public WordAdapter(Context context, List&lt;Word&gt; 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) -&gt; {
stopPlaying();
mediaPlayer = MediaPlayer.create(this.context, this.words.get(position).getAudioResourceId());
mediaPlayer.setOnCompletionListener((mp) -&gt; {
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 &amp;&amp; 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?

答案1

得分: 3

@Override
public void onViewDetachedFromWindow(@NonNull ViewHolder holder) {
    super.onViewDetachedFromWindow(holder);
    stopPlaying();
}

在这里你正在设置停止播放器

`ViewHolder`在屏幕上不可见时触发

你应该在Activity中拥有播放器实例并通过适配器的接口回调监听器模式来控制它

此外使用单个媒体播放器而不是在`VH`内部使用多个对于性能会更好

回调应该像这样
```java
interface PlayableItemCallback {
 void onItemVisible(int position);
 
 void onPlay(int position);
 
 void onStop(int position);
}

在你的Activity中实现它,并在适配器中传递它以控制你的MediaPlayer。Activity代码:

public class NumbersActivity extends AppCompatActivity implements PlayableItemCallback {
    MediaPlayer mediaPlayer;
    Adapter adapter = new Adapter(this);

    //    .............
    @Override
    public void onItemVisible(int position) {

        // 对播放器进行操作
    }

    @Override
    public void onPlay(int position) {
        // 对播放器进行操作
    }

    @Override
    public void onStop(int position) {
        // 对播放器进行操作
    }
}

<details>
<summary>英文:</summary>
@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
}

}


</details>
# 答案2
**得分**: 1
你可以使用 `stopPlaying` 方法来停止媒体播放器。要使其正常工作,您需要创建适配器的实例,并在 `onStop()` 调用时从适配器中调用该方法,完成操作!!!
**创建适配器实例**
```java
private WordAdapter mWordAdapter;
mWordAdapter = new WordAdapter(this, words);
listView.setAdapter(mWordAdapter);

在您的活动中覆盖 onStop 方法

@Override
protected void onStop() {
    super.onStop(); 
    if(mWordAdapter!=null){
        mWordAdapter.stopPlaying();
    }
}

stopPlaying 方法设置为公共方法,以便通过对象访问它。

public void stopPlaying() {
    if (mediaPlayer != null && mediaPlayer.isPlaying()) {
        mediaPlayer.stop();
        mediaPlayer.reset();
        mediaPlayer.release();
        mediaPlayer = null;
    }
}
英文:

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 &amp;&amp; mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}

huangapple
  • 本文由 发表于 2020年4月6日 15:19:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/61054751.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定