Service
布局文件中定义了四个按钮,分别设置了对应的监听事件:startService(),stopService(),bindService(),unbindService()。
在 MyService 的回调方法中打印该方法名以及对应线程。
测试:
点击顺序:
Start -> Stop
可知 Service 的几个回调方法都是在 UI 线程中进行的,所以在这些方法中不可直接进行耗时操作。
点击顺序:
Start -> Start -> Stop
可知当 Service 对象存在时,再次 startService() 并不会创建新的对象,而是再回调一次 onStartCommand() 方法。
点击顺序:
Bind -> Unbind
可知没有 Service 对象时,直接绑定会自动创建对象,用这种方式创建的 Service 对象在解绑时会自动销毁。Start -> Bind -> Unbind 的方式创建并绑定,解绑时 Service 对象不会被销毁。
点击顺序:
Bind -> Back
可知在 Activity 销毁时,Service 对象会自动解绑,绑定时自动创建的 Service 对象会在此刻被销毁。Start -> Bind -> Back 的方式创建并绑定,Activity 被销毁,Service 自动解绑时不会被销毁。
点击顺序:
(Start ->) Bind -> Bind
并不会多次打印 onBind,可知绑定时,Service 对象会检查是否已经与该 Activity 绑定,若已经绑定,则不会重复执行。
点击顺序:
Start -> Bind -> Unbind / Back -> Bind (重写 onUnbind(),让其返回 true,onRebind() 才会被回调!)
如果是直接 Bind -> UnBind -> Bind 的顺序执行,并不会回调 onRebind() 函数,因为在解绑时 Service 就已经被销毁了,再 Bind 只能创建一个新的 Service 对象!
点击顺序:
Start -> Bind -> Stop -> UnBind / Back
当 Service 对象和 Activity 对象绑定时,调用 stopService() 方法并不能直接销毁 Service 对象,但也不是毫无作用,而是推迟到 Service 对象和 Activity 对象解绑时销毁。
IntentService
在 MyIntentService 的 onCreate()、onStartCommand()、onDestroy() 方法中打印对应方法名。
注意onStartCommand() 方法 return 不能做修改,因为使 Message 对象携带 Intent 对象并将其放入消息队列中的过程是在 super.onStartCommand(intent, flags, startId) 中处理的。IntentService 对应代码如下:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
重写 onHandleIntent() 方法:
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Log.d("TAG", "onHandleIntent: " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
连续启动该 MyIntentService 3 次:
每一次启动都会回调 onStartCommand() 方法,在该方法中,Intent 对象被 Message 对象携带进入了消息队列中,然后依次进行处理,在处理完所有请求后 IntentService 对象会自动被销毁。同时我们可以发现,onHandleIntent() 方法不是在 UI 线程中运行的,而是在单独创建的 worker 线程中处理请求,所以在此处进行耗时操作不会阻塞 UI 线程。