在项目中有这样一个需求,就是在列表中点击一首歌会跳到歌曲的详情页进行播放,关于音频播放常用的做法就是用service来进行播放,activity与service直接建立一个中间人对象,通过中间人来控制音乐的播放与暂停或者上一首,下一首。
在播放代码中一般对MediaPlayer对象进行如下设置:
mediaPlayer.setDataSource(url);
mediaPlayer.setOnPreparedListener(mOnPreparedListener);
mediaPlayer.setOnCompletionListener(mOnCompletionListener);
mediaPlayer.setOnErrorListener(mOnErrorListener);
mediaPlayer.prepareAsync();
在实际运用过程中发现当我点击第一首播放的时候,会自动播放下一首,第一首不会播放。对播放的监听里面打log发现,一开始播放第一首的时候直接不会走PreparedListener的监听而是直接走了CompletionListener的监听。但是当我在当前界面而不进入详情页,通过startService来进行播放的时候就没有问题。
然后进行谷歌,上面说prepareAsync( )方法是一个异步操作,用prepared( )方法才会走PreparedListener的监听,遂将prepareAsync()方法改为prepared( )。这个时候问题貌似解决了,但是后面还有更大的坑在等着我。。。。
因为prepared( )在主线程中是个耗时操作,原先的时候在音乐详情页的activity中oncreat( )下通过bindservice 跟 startservice来进行音乐的播放。当我们点击当前列表条目的时候,需要等待4 5 秒才能进入音乐详情页进行音乐的播放。
很显然这样是不符合我们的预期的,经过打断点调试发现问题就出在startservice( )调用之后再在service里面的mediaplayer调用prepared( )方法所致。当时开发比较紧张,先用handler的postdelayed( )方法延迟500毫秒加载startService( )方法。
至此可以现在打开音乐详情的界面,然后进行播放了。但是这样也是治标不治本,prepared( )还是运行在主线程,等待播放的时候还是需要等待4 5 秒钟,很容易造成ANR。并且在测试环境下,有可能后台给的歌曲地址不正确播放不出来的时候,app就会假死,尽管我设置了出错的监听。
本质上还是要把prepared( )方法改为prepareAsync( ),经老大研究别的开源项目指点,将CompletionListener放在PreparedListener里面,代码如下:
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(mOnPreparedListener);
mediaPlayer.setOnErrorListener(mOnErrorListener);
private MediaPlayer.OnPreparedListener mOnPreparedListener = new MediaPlayer.OnPreparedListener( ) {
@Override
public void onPrepared(MediaPlayer mp) {
OnCompletionListener(mOnCompletionListener);
}
};
自我感觉的话应该是异步的时候还没准备好就直接进行CompletionListener了,上面代码这样操作的时候就相当于准备好了以后才能进行播放完成的监听。
因为音频播放的问题相对来说开发的比较少,谷歌的很多都是基础的播放问题,还是需要自己多多琢磨啊。
前人栽树后人乘凉,以后就会少走很多弯路,共勉