IntentService

面试题:场景需要在子线程中依次执行多个子任务,要保证任务时序,所有子任务执行完毕该线程自动退出,怎么实现?

IntentService扩展自Service,是Service和HandlerThread的结合体,天生就在自线程中,且完成任务后自动停止,适合处理自线程耗时任务。如果多次启动IntentService,则每一个任务会以队列的方式在onHandlerIntent方法中依次执行。

原理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    @UnsupportedAppUsage
    private volatile ServiceHandler mServiceHandler;
    private String mName;

    // 子线程Handler
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            //收到消息后调用onHandleIntent方法
            onHandleIntent((Intent)msg.obj);
            //任务执行完毕后关闭自己,注意这里的参数
            stopSelf(msg.arg1);
        }
    }

    /**
     * 构造方法需要传递线程名称
     */
    public IntentService(String name) {
        super();
        mName = name;
    }


    @Override
    public void onCreate() {

        // 初始化一个HandlerThread
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();

        // 用子线程的Looper初始化了子线程的Handler
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    

    /**
     * 直接调用onStart方法
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    /**
     * 主要是把任务封装成消息,发送给子线程处理
     */
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * 退出时关闭子线程Looper,使线程终止
     */
    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    /**
     * 一般不需要用这个方法,也可以通过重写实现
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 我们需要重写这个方法去实现业务逻辑
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

原理很简单:

在创建service时,onCreate方法是必须只调用一次的,所以在这里初始化了一个HandlerThread和归属于他的Handler。

当我们在activity中每次调用startService(),会回调service的onStartCommand()方法,在其中调用了onStart(),把intent封装成消息发送给子线程。由于消息没有when参数限制延迟时间,所以消息在MessageQueue中是按照FIFO(先进后出)的顺序排列的。

当消息经过Looper传递到Handler的HandlerMessage()方法时,会调用onHandleIntent()方法由我们自己去处理。处理完之后会尝试销毁service。

在销毁service时传递了startID,此时系统会检查service中是否还有其他的startID,如果有的话就不会退出,好让剩余的任务继续执行;如果没有,则会销毁Service.