Android MediaPlayer 播放器网络音频播放总结

        在近期的Android 系统MediapPalyer使用中,碰到了不少问题。其中一些问题也是在特殊的条件下才会出现,尝试很多方法才解决。这里做了总结,也跟大家分享一下:

1.播放器需要多线程实现

        一般我们会把MediaPlayer放到Service中,做播放相关的逻辑操作。但是因为Service也是在主线程中,如果播放器内部发生阻塞就会导致整个UI线程阻塞。尤其播放网络资源的时候,播放器的prepare()方法会缓存足够的资源才会播放。这里建议新建一个播放线程控制MediaPlayer的播放。这里我是通过android.os.HandlerThread和Handler实现控制子线程播放操作。

2.网络问题较差时,mediaPlayer.prepare()阻塞线程问题的解决

           楼主开始调用播放代码如下。经过测试当网速不好的情况下(10kB)一下。播放线程会卡在

 mediaPlayer.prepare()的内部方法中。期间使用了几个方法:
     1.将mediaPlayer.prepare()换成mediaPlayer.prepareAsync()使用异步准备的方式。经过测试用异步的方式,当频繁切换的时候界面会出现ANR。原因应该是多线程控制的问题。经过查资料需要在mediaPlayer.reset()之前调用stop的方法。这样做的确界面不ANR,但是因为调用的状态不合法会出现IllegalStateException异常。并且这样也会让播放器内部出现问题。在调用mediaPlayer.setDataSource(path)的时候返回各种不同的错误。

 

      try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(path);
            mediaPlayer.prepare();
            mediaPlayer.start();
        catch (IllegalArgumentException e) {
        }
        catch (SecurityException e) {
        }
        catch (IllegalStateException e) {
        }
        catch (IOException e) {
        }
        catch (NullPointerException e) {
        }
        2.因为第一种方案问题更多,之后我还是继续使用 mediaPlayer.prepare()方法。想通过线程的中断来解决问题。因为是阻塞在MediapPalyer的内部只能通过两种方案,一种就是让MediapPalyer内部报异常,一种就是强制结束线程。这里尝试第一种方案的时候发现。当播放线程阻塞的时候 mediaPlayer.prepare() ,在主线程调用 mediaPlayer.stop()方法可以让prepare方法报 IllegalStateException(经过测试这个是必现的,API中有stop方法调用合法状态)。解决方案具体如下:当播放新歌曲的时候,如果发现播放线程阻塞了,也就是当前的状态是preparing状态,主线程中调用mediaPlayer.stop()方法结束子线程阻塞,销毁掉当前的播放器,重新初始化播放器。延迟1s后播放新的歌曲。这里做延迟的原因是为了防止界面频繁点击新的歌曲。如果不延时,将会在初始化的地方出现ANR。

            //让阻塞的播放线程报异常结束注册
            mediaPlayer.stop();
            //这里必须起线程调用release不然多次调用之后,会出现ANR
            final MediaPlayer releaseMediaPlayer = mediaPlayer;
            new Thread() {
                public void run() {
                    releaseMediaPlayer.release();
                };
            }.start();
          //重新初始化的原因是因为抛出异常之后播放器内部会出现问题,几次之后就报错误无法播放。
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setOnCompletionListener(this);
            mediaPlayer.setOnErrorListener(this);
            mediaPlayer.setOnBufferingUpdateListener(this);
            mediaPlayer.setOnInfoListener(this);
            mediaPlayer.setOnPreparedListener(this);
        }
        catch (Exception e) {
            e.printStackTrace();
        }

3.MediapPalyer OnPreparedListener的作用
        因为我是调用的 mediaPlayer.prepare();方法,所以就没有在OnPreparedListener回调方法Onprepared方法中调用mediaPlayer.start()方法进行播放。在部分的android设备上也是没有问题的。但是经过测试有个设备会偶现mediaPlayer(-38,0)错误(这里错误是在执行prepare()的方法时出现,还没有执行到start()方法)。通过log也发现。如果顺序执行,mediaPlayer.start()方法的确是执行onPrepared方法之前。然后我就把mediaPlayer.start()写到Onprepared()的回调方法中。经过测试不会出现这个偶现的问题。在这里问题解决方案存在疑问,也请大神们指点一下。

4.mediaPlayer.getCurrentPosition()播放过程中会出现的误差
       为了实现一个当播放器播放到最大缓冲的位置(播放器之后不能再播放)提示“加载中”。这里简单的实现了一下,大致的方案如下:在刷新播放进度的方法中,判断当前的播放进度和上一次的播放进度。如果当前精度小于等于上一次的播放进度,就提示“加载中”。经过测试发现,网络较差时的确存在本次播放进度比上一次播放进度小的问题,差值有时候会很大会有几s左右。具体原因不可知。这里也请大家提供合理的解决方案。




 

       

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的 Android MediaPlayer 播放器代码示例: ```java public class MainActivity extends AppCompatActivity implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener { private MediaPlayer mediaPlayer; private Button playButton, pauseButton, stopButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); playButton = findViewById(R.id.button_play); pauseButton = findViewById(R.id.button_pause); stopButton = findViewById(R.id.button_stop); mediaPlayer = new MediaPlayer(); mediaPlayer.setOnPreparedListener(this); mediaPlayer.setOnCompletionListener(this); playButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { mediaPlayer.setDataSource("https://example.com/audio.mp3"); mediaPlayer.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } } }); pauseButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mediaPlayer.pause(); } }); stopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mediaPlayer.stop(); } }); } @Override public void onPrepared(MediaPlayer mp) { mp.start(); } @Override public void onCompletion(MediaPlayer mp) { mp.stop(); } @Override protected void onDestroy() { super.onDestroy(); mediaPlayer.release(); mediaPlayer = null; } } ``` 这个示例中,我们创建了一个包含三个按钮的简单 UI,分别用于播放、暂停和停止音频。当用户点击“播放”按钮时,我们使用 MediaPlayer 的 `setDataSource()` 方法设置音频文件的 URL,然后调用 `prepareAsync()` 方法异步准备播放器。在准备完成后,MediaPlayer 会触发 `onPrepared()` 方法,我们在这里调用 `start()` 方法开始播放音频。当音频播放完毕时,MediaPlayer 会触发 `onCompletion()` 方法,我们在这里调用 `stop()` 方法停止播放器。在 Activity 销毁时,我们需要释放 MediaPlayer 对象以释放资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值