IntentService 示例与详解

96
jacky123
2016.07.09 15:49* 字数 811

为什么要用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();
}

参考资料

四大组件相关