安卓播放器实现后台播放服务

安卓开发,除了我们经常写的Activity、Fragment等显示给用户的控件外,我们还可能需要程序在退出到后台的时候,继续给用户提供服务的功能,这里就需要用到Android的服务Service。
安卓服务是对用户不可见的,它没有界面,只是开启了一个在后台持续运行的线程,就算用户退出到后台,只要不停止服务,服务就可以继续为用户提供服务。不像Activity会有固定的生命周期,当用户把程序退出到后台,程序失去焦点之后,Activity就必须调用onStop方法,失去与用户的交互关系。
下面我们就来实现一个在后台播放的服务:
其实,我想大家学习服务其实都会有一个理解误区,就是服务Service和Activity到底的区别在哪里?是没有界面,还是会一直执行onStartCommand方法,让线程在后台持续执行?
也就是说,只要我们手动的stratService或者bindService来开启服务之后,这个我们继承自系统的Service的服务就会一直持续不断的调用onStartCommand方法,直到我们手动的调用stopService或者调用服务的stopSelf结束服务才会停止运行。
我想大家一定也会和我一样存在上面的误区,但是我们可以来做个实验:

class DifferentSpeedPlayerService : Service() {

    private var playerType: String? = null
    private val mMediaResoureceOne = "https://qiniu.fjreading.com/summary/audio/73cd583f9822fde89936ed5dc59317dc"
    private val mMediaResoureceTwo = "https://qiniu.fjreading.com/summary/audio/b76d0070f7a77ad96f1e3d53c62306d0"
    private val mMediaResoureceThere = "https://qiniu.fjreading.com/summary/audio/04df5b8d56d050e981beeb2b7aefaed7"

    override fun onBind(intent: Intent?): IBinder? {
      LogUtils.e(">>>>>>>>>>>>>>>","绑定服务,返回IBinder对象")
        //获取传递过来的参数来返回不同的播放器对象
         if(ObjectUtils.isNotEmpty(intent)){
             val bundle = intent?.extras
             playerType = bundle?.getString("player_type")
             LogUtils.e(">>>>>>>>>>>>>>>>", "palyer_type:$playerType")
         }
        return LocalBinder()
    }

    /**
     * 客户端 Binder 对应的类
     */
    inner class LocalBinder : Binder() {
        internal// 返回 LocalService 的实例,客户端可以调用其中的公共方法
        val service: DifferentSpeedPlayerService
            get() = this@DifferentSpeedPlayerService
    }
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        LogUtils.e(">>>>>>>>>>>>>>>","onStartCommand Int:"+Int+"startId:"+startId)
        return super.onStartCommand(intent, flags, startId)
    }
    fun getDifferentPlayerByPLayerType(): IPlayerWapper?{
        var player= DifferentSpeedPlayer.getSpeedPlayerInstance()
        player?.initPlayer(baseContext)
        player?.prepareDataSource(mMediaResoureceTwo,250)
        return player as IPlayerWapper
    }

    override fun onConfigurationChanged(newConfig: Configuration?) {
        super.onConfigurationChanged(newConfig)
        LogUtils.e(">>>>>>>>>>>>>>>", "newConfig:$newConfig")
    }

    override fun onRebind(intent: Intent?) {
        super.onRebind(intent)
        LogUtils.e(">>>>>>>>>>>>>>>", "onRebind")
    }

    override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
        super.dump(fd, writer, args)
        LogUtils.e(">>>>>>>>>>>>>>>", "dump")
    }

    override fun onCreate() {
        super.onCreate()
        LogUtils.e(">>>>>>>>>>>>>>>", "onCreate")
    }

    override fun onLowMemory() {
        super.onLowMemory()
        LogUtils.e(">>>>>>>>>>>>>>>", "onLowMemory")
    }

    override fun onTaskRemoved(rootIntent: Intent?) {
        super.onTaskRemoved(rootIntent)
        LogUtils.e(">>>>>>>>>>>>>>>", "onTaskRemoved")
    }

    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)
        LogUtils.e(">>>>>>>>>>>>>>>", "level:$level")
    }

    override fun onUnbind(intent: Intent?): Boolean {
        LogUtils.e(">>>>>>>>>>>>>>>", "intent:$intent")
        return super.onUnbind(intent)
    }
    override fun onDestroy() {
        super.onDestroy()
        LogUtils.e(">>>>>>>>>>>>>>>", "onDestroy")
    }

上面的服务重写了Service类的所有的方法,下面就来测试一下,startService和bindService方法开启服务的不同点在于调用的Service的方法不同。
startService方法开启服务会调用服务的onCreate方法来创建一个服务,然后再调用服务的onStartCommand方法来运行服务,值得注意的是:onCreatef方法只会调用一次,onStartCommand方法在你重复调用startService方法会重复执行。
但是这里你已经得到了开启服务的效果,如果是播放音乐,无论手机是熄屏还是App退出到后台,你播放音乐的服务线程不会受到影响,这里你只要不手动调用stopService方法,服务就会持续运行在后台。
调用bindService方法来开启服务,首先也会调用服务的onCreate方法,然后调用服务的onBind方法,来返回一个继承自Binder对象的子类。我们可以在绑定服务的时候用继承ServiceConnection的子类链接对象里面获取到Service里面定义的LocalBinder对象,然后通过这个LocalBinder对象获取Service对象。这样我们就可以拿到定义在服务里面的成员变量,这里这个成员变量可以是一个播放器和可以是一个在后台运行的线程。

 class DifferentSpeedServiceConnection : ServiceConnection{

        var mDifferentSpeedPlayer: DifferentSpeedPlayer? = null
       override fun onServiceDisconnected(name: ComponentName?) {

           LogUtils.e(">>>>>>>>>>>>>>>", "onServiceDisconnected:$name")
       }

       override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
           try {
               val localBinder = service as DifferentSpeedPlayerService.LocalBinder
               val articlePlayerService = localBinder.service
               mDifferentSpeedPlayer =  articlePlayerService.getDifferentPlayerByPLayerType() as DifferentSpeedPlayer?
               mDifferentSpeedPlayer?.startPlay()
               LogUtils.e(">>>>>>>>>>>>>>>", "组件名称:$name" + "绑定的服务:" + service)
               LogUtils.e(">>>>>>>>>>>>>>>", "mDifferentSpeedPlayer" +mDifferentSpeedPlayer)
           }catch (e: Exception){
               Log.e(">>>>>>>>>>>>>>", "绑定服务异常:$e")
           }
       }
   }

这里获取我们可以思考一下,为什么我们不能直接通过ServiceConnection对象来获取Service对象,而是需要在Service里面定义一个Binder对象的子类,然后通过onBindf方法来返回到ServiceConnection的onServiceConnected(name: ComponentName?, service: IBinder?) 方法呢?这里我们会发现了共同对象IBinder,然后发现IBinder对象是一个接口,这就说明服务和组件或者界面绑定是通过public interface IBinder {}接口来实现绑定的。
我们解绑时需要传递一个ServiceConnection对象来取消绑定。
但是,有时候我们可能会用到一些第三方服务,比如百度语音合成、百度定位等,这些第三方服务其实都是有自己的服务,所以就不需要再自己去开启一个服务来处理逻辑,只需要按照第三方的开发文档进行集成就行?根据按照开发经验,如果播放器没有开启后台服务,程序退出到后台,调用第三方的服务也会经常报错,所以说明安卓客户端如果需要实现一个播放器,就需要在后台开启一个后台服务来实现后台播放功能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android音乐播放器实现可以分为以下步骤: 1. 获取音乐文件 首先,需要获取存储在设备上的音乐文件。可以使用Android的MediaStore类来访问设备上的媒体文件,包括音乐、视频和图片等。 2. 播放音乐 使用MediaPlayer类来播放音乐。MediaPlayer是Android提供的一个用于播放音频和视频的类,可以实现音乐的播放、暂停、停止等功能。 3. 显示音乐列表 可以使用ListView或RecyclerView来显示音乐列表,其中每个列表项包含音乐文件的名称、歌手、专辑封面等信息。 4. 控制音乐播放 在音乐播放器界面上添加控制按钮,如播放、暂停、停止、上一曲、下一曲等按钮,通过点击按钮来控制音乐的播放。 5. 实现后台播放 通过Service来实现音乐的后台播放,即使应用处于后台或者设备锁屏,音乐仍然可以继续播放。 6. 实现通知栏控制 在通知栏中添加音乐控制按钮,可以在不打开应用程序的情况下控制音乐的播放和暂停等操作。 7. 实现循环播放、随机播放功能 可以在播放器中添加循环播放、随机播放功能,使用户可以根据自己的喜好来选择音乐播放模式。 8. 实现歌词显示 可以通过解析歌词文件来实现歌词的显示,使用户可以在听歌的同时查看歌词。 以上就是Android音乐播放器的基本实现步骤,具体实现过程中需要根据实际情况进行调整和修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值