为什么要用IntentService
IntentService 与 Service 相比的好处:一方面不需要自己去 new Thread 了;另一方面不需要考虑在什么时候关闭该 Service 了。
源码解析
当IntentService第一次启动,它的onCreate方法会被调用,该方法会创建一个HandlerThread,然后使用它的Looper来构造一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行。
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
/**
* HandlerThread ,Handy class for starting a new thread that has a looper。
* 因为HandlerThread是一个Thread,我们调用其start方法就会调用run方法,其中会通过 Looper.myLooper()获取当前线程的looper对象
*/
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
/**
* use the provided {@link Looper} instead of the default one.
*/
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
/**
* 自己停止Service服务
*/
stopSelf(msg.arg1);
}
}
每次启动IntentService,它的onStartCommand方法就会被调用一次,onStartCommand调用了onStart方法。
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
IntentService仅仅通过mServiceHandler发送了一条消息,这个消息会在HandlerThread中处理。mServiceHandler收到消息后,会将Intent对象传递给onHandleIntent方法处理。
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
/**
* use the provided {@link Looper} instead of the default one.
*/
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
/**
* 尝试自己停止Service服务
*/
stopSelf(msg.arg1);
}
}
当onHandleIntent方法执行结束之后,IntentService会尝试通过stopSelf(int startId)来尝试停止服务。之所以不用stopSelf()来停止服务,是因为stopSelf()会立刻停止服务,而stopSelf(int startId)则会等待所有的消息都处理完毕才回终止服务。一般来说,stopSelf(int startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等则立刻停止服务。
2. 为什么不建议通过 bindService() 启动 IntentService?
@Override
public IBinder onBind(Intent intent) {
return null;
}
IntentService 源码中的 onBind() 默认返回 null;不适合 bindService() 启动服务,如果你执意要 bindService() 来启动 IntentService,可能因为你想通过 Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,这样那么 onHandleIntent() 不会被回调,相当于在你使用 Service 而不是 IntentService。
3. 为什么多次启动 IntentService 会顺序执行事件,停止服务后,后续的事件得不到执行?
IntentService 中使用的 Handler、Looper、MessageQueue 机制把消息发送到线程中去执行的,所以多次启动 IntentService 不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行,而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
网友评论