简体   繁体   English

在RecyclerView中播放和释放音频

[英]Playing and Releasing audio in RecyclerView

I'm learning android and currently RecyclerView, so in this example I'm playing a specific raw sound file when clicking a play button and then releasing it when it's done. 我正在学习android,目前正在学习RecyclerView,因此在此示例中,我在单击播放按钮时播放特定的原始声音文件,然后在完成播放时将其释放。 I could seriously use some pointers on what is the best practice however as I have a few issues and questions: 我可能会在最佳做法上认真使用一些指针,但是由于存在一些问题,我会:

  • I have a problem with transiting states so if I press play very quickly I'll get an IllegalStateException , probably from trying to release an already released player. 我在转换状态时遇到问题,因此如果我快速按一下播放键,则会收到IllegalStateException异常,可能是因为尝试释放一个已经释放的播放器。
  • I should apparently also nullify after release and do a null check prior but since I'm using it in a nested scope it has to be declared final and can't be nulled which is confusing, I've obviously missed something. 我显然也应该在发布后使​​它无效,并在执行之前进行检查,但是由于我是在嵌套作用域中使用它,因此必须将其声明为final,并且不能将其设为空,这会造成混淆,我显然错过了一些东西。
  • setting the clickListner on an item in onBindViewHolder also seems significantly slower and less responsive than adding a clickListner on the entire row in the viewHolder class. 与在viewHolder类的整个行中添加clickListner相比,在onBindViewHolder中的项目上设置clickListner似乎也明显慢得多,并且响应速度也较慢。

What is the best practice for setting up your mediaPlayer and managing your resources correctly with RecyclerView and what am I doing wrong that would cause crashes and "slowness"? 使用RecyclerView设置mediaPlayer和正确管理资源的最佳实践是什么,我在做错什么会导致崩溃和“缓慢”?

//ViewHolder // ViewHolder

public static class myHolder extends RecyclerView.ViewHolder implements View.OnClickListener{


    ImageView playBtn;

    public myHolder(View v){
        super(v);
        playBtn = (ImageView) v.findViewById(R.id.playBtn);
        v.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
    }

}

//onBindViewHolder / onCompletionListener // onBindViewHolder / onCompletionListener

  @Override
public void onBindViewHolder(myHolder holder, int position) {
    myClass item = itemList.get(position);
    final MediaPlayer mediaPlayer = MediaPlayer.create(holder.itemView.getContext(), item.getAudioSource());

   holder.playBtn.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {

            mediaPlayer.start();
            mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mp.release();
                }
            });
        }
    });
}

If you're only listening in user interaction you can drop setOnCompleteListener() and instead define your play/stop code in (in order) OnLongClickListener() and OnClickListener . 如果仅在用户交互中进行监听,则可以删除setOnCompleteListener() ,而是按顺序(按顺序) OnLongClickListener() / OnLongClickListener()OnClickListener播放/停止代码。 Like this: 像这样:

holder.playBtn.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {
       //Code to stop playing and release resources
    }
});

holder.playBtn.setOnLongClickListener(new View.OnClickListener(){
        @Override
        public void onLongClick(View v) {
           //Code to start playing 

           return false; //!!This is important so that OnClick() would be called after releasing the button
        }
    });

OBS As I'm answering my own question I can NOT say that this is acctualy good practice but it did solve the issues I was having, if anyone spots an error or has a better more efficient way then please post an answer and elaborate. OBS在回答我自己的问题时,我不能说这是一种非常好的做法,但是它确实解决了我遇到的问题,如果有人发现错误或有更好的更有效的方法,请发表答案并进行详细说明。

  • instead of declaring the MediaPlayer inside the onBindViewHolder I made it a class variable, this allowed me to avoid having it final and be able to nullify it after release. 我没有在onBindViewHolder中声明MediaPlayer,而是将其设置为类变量,这使我避免将其定型,并可以在发布后使​​其无效。
  • I then defined it inside the onClick method instead to make sure that it would never be null and always be declared when needed. 然后,我在onClick方法中定义了它,以确保它永远不会为null并始终在需要时进行声明。
  • I had to make my holder and "item" final in order to use them inside the onClick but this seems to have worked (recyclerView magic I guess) 为了在onClick中使用它们,我必须将其持有人和“ item”定为决赛,但这似乎行得通(我猜是recyclerView魔术)

The app no longer crashes and onCompletionListener should clear all resources, this is the current code: 该应用不再崩溃,onCompletionListener应该清除所有资源,这是当前代码:

//class variable mediaplayer and onCompletionListener method //类变量mediaplayer和onCompletionListener方法

MediaPlayer mediaPlayer;

//onCompletionListener method
MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mp) {
        mp.release();
        mediaPlayer = null;
    }
};

//onBindViewHolder // onBindViewHolder

@Override
public void onBindViewHolder(final itemHolder holder, int position) {
    final Items item = mItemList.get(position);

    holder.playBtn.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            mediaPlayer = MediaPlayer.create(holder.itemView.getContext(), item.getAudioSource());
            if(mediaPlayer != null) {
                mediaPlayer.start();
                mediaPlayer.setOnCompletionListener(mCompletionListener);
            }
        }
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM