文章目录
背景
项目原因,现在需要将播放器放到一个单独的进程中,主要方案有两种:
- 使用两个Activity,播放器所在的Activity在下,上面的Activity主题使用透明主题,该方案是最简单的,但是使用时有以下几个注意事项:
- 上层Activity透明主题设置问题
如果Activity是直接继承自Activity类,只需在XML中声明主题为透明主题即可:
<activity
...
android:process=":XXXXX"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
...
>
</activity>
如果Activity是继承自AppCompatActivity,除了在xml中声明一下外,还要在代码中再设置一下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.ActivityTransparent);
}
<style name="ActivityTransparent" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowFullscreen">true</item>
</style>
- 两个Activity信息传输:两个Activity之间的通信用aidl,这边没有用Messenger,因为Messenger是基于消息队列的,如果上面需要获取播放器当前播放位置,就需要线程阻塞来等待播放器返回消息,增加线程消耗。
- Activity的生命周期:上层的Activity生命周期是正常的,但是下层的生命周期和Android分屏相似,是处于onPause阶段,不会走onStop,因为上层Activity是透明主题,下层界面对于用户来说是可见但不可操作。
- 使用一个Activity,播放器在一个service中,Activity中创建好SurfaceView并将Surface传递给service,因为Surface默认已经实现了Parcelable接口,所以使用AIDL可以直接传递,下面的实例也是基于这种方案的。
播放器放在Service中实现
- 先写一个播放器,这边使用最简单的MediaPlayer
package com.dean.playerdemo.player
import android.media.MediaPlayer
import android.view.Surface
class SmartMediaPlayer(val surface: Surface): MediaPlayer.OnPreparedListener{
val mPlayer = MediaPlayer().apply {
setOnPreparedListener(this@SmartMediaPlayer)
//setScreenOnWhilePlaying(true) 使用的是surface,该方法实现,需要使用其他方式实现播放中屏幕常亮
setSurface(surface)
}
fun start(url: String){
if (mPlayer.isPlaying){
mPlayer.stop()
}
mPlayer.reset()
mPlayer.setDataSource(url)
mPlayer.prepareAsync()
}
fun resume(){
mPlayer.start()
}
fun pause(){
mPlayer.pause()
}
fun stop(){
mPlayer.stop()
}
fun releasePlay(){
mPlayer.release()
}
fun getCurrentPosition() = mPlayer.currentPosition
override fun onPrepared(mp: Med