IntentService为何物?
熟悉Android的人都知道,Androi系统为我们提供了一个专门处理后台耗时任务的组件,即Service。使用它可以很方便的完成一些需要长期执行但是却不需要UI界面的任务,比如音乐播放、同步数据库等等。那么我们今天的主角IntentService到底是何方神圣呢?
重要点梳理
首先我们来看一下类的签名1
public abstract class IntentService extends Service {}
由此可知IntentService其实是一个Service,它继承自Service拥有Service的所有特性,当然青出于蓝而胜于蓝,IntentService比Service强大的地方在哪里呢?接着往下看:
ServiceHandler
IntentService有一个内部类1
2
3
4
5
6
7
8
9
10
11private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
可以看到ServiceHandler继承自Handler,实现了它的handleMessage方法,就是说IntentService内部实现了一套线程间发送消息和处理消息的机制。但是它只是处理了特定的事件即stopSelf。大家都知道stopSelf为Service处理完成释放资源的方法。不错,IntentService为我们启动了Service的“自毁”程序。
onCreate操作
既然有了Handler消息的处理,那么是怎么初始化Handler的呢?请看:1
2
3
4
5
6
7
8
9
10
11
12
13
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 thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
在这个onCreate方法中初始化了一个HandlerThread,此处如果不理解HandlerThread是什么,可以简单理解为一个自带Handler功能的Thread,是的,它就是一个线程。这里通过实例化HandlerThread新建线程并启动,所以使用IntentService时不需要额外新建线程,并且拿到工作线程的Looper维护自己的工作队列,最后将Looper与新建的ServiceHandler绑定由其分发处理事件。
由于onCreate()方法只会调用一次,所以只会创建一个工作线程;当多次调用 startService(Intent) 时(onStartCommand也会调用多次)其实并不会创建新的工作线程,只是把消息加入消息队列中等待执行,所以,多次启动 IntentService 会按顺序执行事件。
onCreate操作
处理消息、以及Handler都准备好了,那么我们的消息到底是在什么时候添加的呢?1
2
3
4
5
6
7
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
从这里我们就能知道,每当启动一个IntentService时会把intent包装到message的obj中,然后发送消息,即添加到消息队列里。最后在消息处理的时候拿出这个intent作为事件处理的参数。参见ServiceHandler的handleMessage方法。
Redelivery
除此之外IntentService还额外附赠了一个setIntentRedelivery方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
在源码中我们可以发现,该方法改变了boolean变量mRedelivery的值,而mRedelivery得值关系到onStartCommand的返回变量。1
2
3
4
5
6
7
8
9
10
11/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
可以看到,mRedelivery不同,会返回两个不同的标志START_REDELIVER_INTENT 和START_NOT_STICKY,那么他们有什么不同呢?
区别就在于如果系统在服务完成之前关闭它,则两种类型就表现出不同了:
START_NOT_STICKY型服务会直接被关闭,而START_REDELIVER_INTENT 型服务会在可用资源不再吃紧的时候尝试再次启动服务。由此我们可以发现,当我们的操作不是十分重要的时候,我们可以选择START_NOT_STICKY,这也是IntentService的默认选项,当我们认为操作十分重要时,则应该选择START_REDELIVER_INTENT 型服务。
与Service的异同
1、Service任务默认执行于应用程序的主线程,而IntentService会创建一个工作线程来处理任务
2、Service需要主动调用stopSelft()来结束服务,而IntentService不需要(在所有intent被处理完后,系统会自动关闭服务)
3、此外:
IntentService为Service的onBingd()方式提供了默认实现:返回null
IntentService为Service的onStartCommand()方法提供了默认实现:将请求的intent添加到队列中
使用方法
由于IntentService为抽象类,因此我们在使用时必须继承它并实现它的onHandleIntent方法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
45import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
public class MyIntentService extends IntentService {
public MyIntentService() {
//构造函数参数为工作线程的名字
super("myIntentService");
}
//实现耗时任务的操作
protected void onHandleIntent(Intent intent) {
//根据Intent的不同进行不同的事务处理
String taskName = intent.getExtras().getString("taskName");
switch (taskName) {
case "task1":
//do something
break;
case "task2":
//do something
break;
default:
break;
}
}
public void onCreate() {
super.onCreate();
}
//默认实现将请求的Intent添加到工作队列里
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
public void onDestroy() {
super.onDestroy();
}
}
可以看到很简单的继承只需要实现自己的onHandleIntent方法就可以了,然后使用它也很简单:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//同一服务只会开启一个工作线程
//在onHandleIntent函数里依次处理intent请求。
Intent i = new Intent("balabala");
Bundle bundle = new Bundle();
bundle.putString("taskName", "task1");
i.putExtras(bundle);
startService(i);
Intent i2 = new Intent("balabala");
Bundle bundle2 = new Bundle();
bundle2.putString("taskName", "task2");
i2.putExtras(bundle2);
startService(i2);
startService(i); //多次启动,会将i再次加入到消息队列,处理,然后分发结果
坑
IntentService中,onBind()是默认返回null的,而采用bindService() 启动 IntentService的生命周期是:onCreate()—>onBind()—>onunbind()—>onDestory(),并不会调用onstart()或者onstartcommand()方法,所以不会将消息发送到消息队列,那么onHandleIntent()将不会回调,即无法实现多线程的操作。切记!