Service 的两种启动方式和「Service 与 Activity 数据交互」

本文深入探讨了Android中Service的启动方式与生命周期,包括startService和bindService的区别及混合使用场景。同时,详细讲解了Service与Activity之间的数据交互方法,如通过接口回调和服务引用进行通信。

1. Service 的两种启动方式

Activity 中可以有两种方式启动 Service,不同方式启动时 Service 的生命周期也不一样,现在在 Activity 中定义四个 Button,分别是 startServicestopServicebindServiceunbindService,Service 中各生命周期中分别打印 Log 日志,通过日志查看生命周期执行情况:

// MainActivity.kt
class MainActivity : AppCompatActivity(){
    var mService: MyService? = null
    var isBind = false
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val intent = Intent(this, MyService::class.java)
        val conn = object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {
                Log.e("abc", "-- Activity 中 onServiceDisconnected --")
            }

            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                mService = (service as MyService.MyBinder).getService()
                Log.e("abc", "-- Activity 中 onServiceConnected --")
            }
        }

        startService.setOnClickListener {
            startService(intent)
        }
        stopService.setOnClickListener {
            stopService(intent)
        }
        bindService.setOnClickListener {
            isBind = bindService(intent, conn, Context.BIND_AUTO_CREATE)
        }
        unBindService.setOnClickListener {
            if (isBind) {
                isBind = false
                unbindService(conn)
            }
        }
    }
}
// MyService.kt
class MyService: Service() {
    override fun onBind(intent: Intent?): IBinder? {
        Log.e("abc", "-- onBind --")
        return MyBinder()
    }

    override fun onCreate() {
        super.onCreate()
        Log.e("abc", "-- onCreate --")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e("abc", "-- onStartCommand --")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.e("abc", "-- onDestroy --")
    }

    override fun onUnbind(intent: Intent?): Boolean {
        Log.e("abc", "-- onUnbind --")
        return super.onUnbind(intent)
    }

    inner class MyBinder : Binder() {
        fun getService(): MyService {
            return this@MyService
        }
    }
}

其实以前 Service 还有个生命周期叫 onStart(),后来被弃用了,它的功能由onStartCommand()代替。

1.1 startService

在 MainActivity 中可以这样启动和停止 Service:

// 启动
val intent = Intent(this, MyService::class.java)
startService(intent)
// 停止
stopService(intent)
// Log
-- onCreate --
-- onStartCommand --
-- onDestroy --

1.2 bindService

bindService 方式稍微复杂些:

// 绑定
val conn = object : ServiceConnection {
    override fun onServiceDisconnected(name: ComponentName?) {}
    override fun onServiceConnected(name: ComponentName?, service: IBinder?) { }
}
bindService(intent, conn, Context.BIND_AUTO_CREATE)
// 停止
unbindService(conn)
// Log
-- onCreate --
-- onBind --
-- onUnbind --
-- onDestroy --

绑定时会执行 onBind 生命周期,解绑时先调用 onUnbind再调用onDestroy

1.3 两种方式混合

如果先用 startService 方式启动了 Service,再用 bindService 绑定一次(两者顺序也可以颠倒),那么此时单纯的 stopService 或者 unbindService 是无法终止 Service 的,需要二者联合使用才行。具体细化:

1.3.1 先 stopService 后unbindService

// Log
-- onCreate --
-- onStartCommand --
-- onBind --

// stopService 无反应

// unbindService:
-- onUnbind --
-- onDestroy --

调用 stopService 没有反应,调用 unbindService 时方可销毁 Service。

1.3.2 先 unbindService 后 stopService

-- onCreate --
-- onStartCommand --
-- onBind --

// unbindService
-- onUnbind --

// stopService
-- onDestroy --

调用 unbindService 只能解绑(onUnbind)不能销毁,调用 stopService 时才可以销毁 Service

1.4 注意事项

  1. 多次调用 startService 时,Service 中的 onStartCommand方法会执行多次;但多次使用 bindService 时,onBind 只执行一次。
  2. bindService 方式打开 Service 时,Service 的生命周期是和打开它的 Activity 绑定的,而 startService 方式打开的 Service 在 Activity 被销毁后(onDestroy),还可以继续存活(可以同时打印 Activity 和 Service 的生命周期查看,这里不举例子了)。

2. Service 与 Activity 数据交互

其实从前面的代码中也可以看出,在 MainActivity 中,可以获取到 Service 的引用(具体来说是onServiceConnected中),Service 调用 Activity 中的方法主要讲讲。

2.1 Activity 调用 Service 方法

回看 Service 的onBind生命周期可以发现,该方法返回的是一个 IBinder 类型,我们在具体实现是返回的是它子类的子类(IBinder 的 子类是 Binder,Binder 的子类是 MyBinder),这是一种多态(不懂多态的自己查一下蛤,这篇文章不是介绍多态的,展开说太长了):

// MyBinder 是 Service 我自己定义的里面的内部类
inner class MyBinder : Binder() {
        fun getService(): MyService {
            return this@MyService
        }
    }
// Binder 源码
public class Binder implements IBinder {
...代码省略
}
// onBind 生命周期
override fun onBind(intent: Intent?): IBinder? {
        return MyBinder()
    }
// bindService 方式打开 Service 时用到的 conn
val conn = object : ServiceConnection {
            override fun onServiceDisconnected(name: ComponentName?) {
            }
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                mService = (service as MyService.MyBinder).getService()
            }
        }

现在,可以用 mService 对象调用 Service 中的任何方法,比如 printTxt

 fun printTxt(txt : String) {
        Log.e("abc", "-- this is txt -- $txt")
    }

其实我觉得还可以直接 new 一个 MyService 对象 mService2,然后 myService2.printTxt("装逼"),好像也没啥区别。

2.2 Service 主动向 Activity 传输数据

Service 没有 Activity 的引用,所以可以通过接口回调或者广播的方式向 Activity 传递数据。

2.2.1 接口回调

定义接口:

interface CallBack {
    fun call(index: Int)
}

Service 中初始化:

private var callBack:CallBack ?= null
fun setListener(callBack: CallBack){
    this.callBack = callBack
}

Activity 实现 CallBack(或者用 匿名内部类):

class MainActivity : AppCompatActivity(), CallBack {
    override fun call(index: Int) {
        Log.e("abc", "This is index value : $index")
    }
}
mService.setListener(this@MainActivity)

// 或者
mService!!.setListener(object :CallBack{
    override fun call(index: Int) {
        Log.e("abc", "This is index value : $index")
    }
})

Service 中有了 callBack 对象,就可以主动向 Activity 传输数据了。

2.2.2 广播

用 Android 自带的 BroadcastReceiver 或者 EventBus 这种第三方框架区别不大,先在 Activity 中注册接受者,然后在 Service 中发射广播数据,不具体举例了。需要说明的是,如果是一个 Service 向多个 Activity 传递数据,广播比回调要好一些。

源码地址

点击查看

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值