最近实现一个音乐播放器的小项目,实现后台播放歌曲的功能,即使退出程序也可以一直播放歌曲,服务不被停止。
实现这个功能的过程中遇到了有两个问题:
问题1、退出程序之后,service播放歌曲的服务在后台执行,但是当屏幕锁屏之后,播放一段时间后,服务被停止,歌曲停止播放。控制台打印输出下面的字符串“QCMediaPlayer mediaplayer NOT present”
问题2、锁屏后,唤醒屏幕,此时歌曲会停止播放,而不是一直播放。
这两个问题都有解决方案。
- 第一个问题解决方法:
在启动播放service的时候,获取电源设备锁,等到停止服务的时候释放电源设备锁。
这个方法需要权限:
< uses-permission android:name=”android.permission.WAKE_LOCK”/>
实例代码如下:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">@Override
public void onCreate() {
super<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.onCreate</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
acquireWakeLock()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;//获取设备电源锁</span>
mSensorManager = (SensorManager) getSystemService(Context<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.SENSOR</span>_SERVICE)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
MusicUtils<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.initMusicList</span>()<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
mPlayingPosition = (Integer) SpUtils<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.get</span>(this, Constants<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.PLAY</span>_POS, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
Uri uri = Uri<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.parse</span>(MusicUtils<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sMusicList</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.get</span>(
getPlayingPosition())<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getUri</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
mPlayer = MediaPlayer<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.create</span>(PlayService<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.this</span>,uri)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
mPlayer<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.setOnCompletionListener</span>(this)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
// 开始更新进度的线程
mProgressUpdatedListener<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.execute</span>(mPublishProgressRunnable)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 申请设备电源锁</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">acquireWakeLock</span>() { L.l(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"正在申请电源锁"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> == mWakeLock) { PowerManager pm = (PowerManager) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span> .getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">""</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> != mWakeLock) { mWakeLock.acquire(); L.l(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"电源锁申请成功"</span>); } } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 释放设备电源锁</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">releaseWakeLock</span>() { L.l(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"正在释放电源锁"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> != mWakeLock) { mWakeLock.release(); mWakeLock = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; L.l(TAG, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"电源锁释放成功"</span>); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>
- 第二个问题解决方法:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*这个问题是版本问题
4.0以上 不要new了
直接create*/</span>
Uri uri = Uri<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.parse</span>(MusicUtils<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sMusicList</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.get</span>(
getPlayingPosition())<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.getUri</span>())<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
mPlayer = MediaPlayer<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.create</span>(PlayService<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.this</span>,uri)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
解决方法就是:mplayer=new MediaPlayer();
改为:mPlayer = MediaPlayer.create(PlayService.this,uri);
即可。
另外值得一提同时,播放歌曲需要读取SD卡数据,所以需要权限:
< uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE”/>
还有一点必须提醒,就是服务的开启,我们知道服务有两种方式启动,一种是startservice()方式启动,这种方式不随着Context的销毁而接触绑定导致服务停止,另一种方式是bindservice()方式,这种方式随着context的销毁而unbindservice,导致服务停止。
我们可以在application类中使用startservice启动所需的服务,然后到需要绑定该服务的Activity中使用bindservice再次绑定该服务,activity销毁时再unbindservice服务,此时并不会stopservice,除非显式调用stopservice方法才会导致服务停止。使用这中方法可以尽可能的提高服务的优先级,使服务一直在后台运行。
最后需要指出的是,以上措施并不能是服务很好的平稳运行,在我手机中采用了以上方法,但是,当我退出程序,app在后台运行,歌曲会一直播放,但是等一段时间后歌曲会停止播放,但是后台服务并没有调用ondestory方法,也就是说服务没有停止。
目前为止,本人了解到,一般开发者开发的app还不能做到一直在后台运行的服务,还不能像QQ,微信这样的APP做到服务一直在后台,无法销毁。这个原因是,一般开发的app并不是手机安全软件所识别,手机安全软件有白名单,这些白名单就是QQ,微信等应用,它的用户量非常多,所以手机安全软件是不会把这些app服务给销毁掉的,而一般app并不是用户所必须的,手机安全软件当然把一般的app服务给销毁掉,不然的话,一般开发者开发的app都能开发一直运行的服务在后台运行的话,手机本身都受不了了!所以在此提醒大家,不要费劲开发service服务一直在后台运行的了,能做到service服务在不清楚内存的情况下能够运行就可以了,而上面的那些方法说明是可以做到的!
上面的解决措施是我亲身测试过的,如果有什么疑问,大家留言,相互交流学习!!^_^【握手】