1. Service 的两种启动方式
Activity 中可以有两种方式启动 Service,不同方式启动时 Service 的生命周期也不一样,现在在 Activity 中定义四个 Button,分别是 startService
、stopService
、bindService
、unbindService
,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 注意事项
- 多次调用 startService 时,Service 中的
onStartCommand
方法会执行多次;但多次使用 bindService 时,onBind
只执行一次。 - 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 传递数据,广播比回调要好一些。