IntentService
MoMo Lv5
  1. IntentService是什么?⭐⭐⭐⭐⭐
  2. IntentService原理和使用场景?⭐⭐⭐⭐
  3. IntentService和Service的区别 ⭐⭐⭐⭐⭐

IntentService是什么?

回顾Android实现线程异步的方法,有AsyncTask、HandlerThread、线程池、IntentService。其中IntentService其实是继承于Service的类,内部是由HandlerThread实现。常用于处理异步请求,处理完子线程的耗时操作后,会自动执行stopService()。

IntentService的使用

  1. 定义 IntentService的子类,需复写onHandleIntent()方法
  2. 在Manifest.xml中注册服务
  3. 在Activity中开启Service服务

用IntentService来实现在后台读取文件已经下载文件:

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
// XuruiIntentService.java
public class XuruiIntentService extends IntentService {

private static final String TAG = "XuruiIntentService";

public XuruiIntentService() {
//IntentService 工作线程的名字
super("XuruiIntentService");
}

@Override
public void onCreate() {
super.onCreate();
}

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent != null) {
String taskName = intent.getStringExtra("taskName");
switch (taskName) {
case "readFile": //1
//任务一:执行读取大文件内容的耗时操作
try {
readFile();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case "DownLoad": //2
//任务二:执行从网络下载文件的耗时操作
break;
default:
break;
}
}
}
}
// Activity中使用XuruiIntentService类
public void onClick(View v) {
Intent intent = new Intent(this, XuruiIntentService.class);
switch (v.getId()) {
case R.id.readFileBtn: //3
intent.putExtra("taskName", "readFile");
startService(intent);
break;
case R.id.downLoadBtn: //4
intent.putExtra("taskName", "DownLoad");
startService(intent);
break;
default:
break;
}
}

在注释3按下读取文件的按钮后,就会通过startService()启动服务,跑到注释1去执行耗时的文件读取操作。没错,IntentService的启动和Service的启动是一样的。

还有一点需要注意,如果按下readFileBtn后马上按downLoadBtn,那么代码执行的顺序是: onCreate、onStartCommand、onHandleIntent: readFile、onStartCommand、onHandleIntent: DownLoad、onDestroy

但如果按下readFileBtn后稍等一会再按downLoadBtn,那么代码执行的顺序是: onCreate、onStartCommand、onHandleIntent: task1、readFile、 onCreate、onStartCommand、onHandleIntent: task2、DownLoad

以上两种情况证明了,IntentService在处理完操作后,会自动退出,因此按下readFileBtn后稍等一会再按downLoadBtn,会重新拉起一个新的服务,从onCreate()开始执行。

:不能用bindService()来绑定IntentService,因为onBind()默认返回null。

源码分析

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;

private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj); //1
stopSelf(msg.arg1); //2
}
}

/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}

/**
* 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;
}

@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 thread = new HandlerThread("IntentService[" + mName + "]"); //3
thread.start(); //4

mServiceLooper = thread.getLooper(); //5.1
mServiceHandler = new ServiceHandler(mServiceLooper); //5.2
}

@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg); //6
}

/**
* 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
*/
@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 onDestroy() {
mServiceLooper.quit(); //7
}

/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}

/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}

IntentService源码:

1
2
3
// 按下readFileBtn后执行:
intent.putExtra("taskName", "readFile");
startService(intent);

启动服务后,流程如下:

  1. 首先执行onCreate(),里面的注释3-5正是HandlerThread三大经典的使用步骤,对应[注释3-5];
  2. 接着执行onStartCommand() -> onStart(),通过子线程的mServiceHandler发送消息,对应[注释6];
  3. 发送信息就有接收信息,执行子线程handleMessage()中调用我们重写的 onHandlerIntent 执行异步任务,对应[注释1];
  4. 等待所有任务执行完后,调用[注释2] stopSelf(msg.arg1)来销毁服务,可以发现该方法带了参数,意为尝试停止服务之前会判断最近启动服务的次数是否是startId,如果相等才停止服务。

因为onCreate()只会执行一次,但onStartCommand()可以执行多次,所以多次调用startService(Intent) 时,上面2-3步骤可能发送和接收多个消息,通过复写onHandlerIntent(),再根据发送不同的Intent,进行不同的线程操作。且发送多个消息时,对应的多个任务需要按顺序逐个执行。

Service 与 IntentService 的区别

  • Service不是单独的线程,如果在onStartCommand()中执行耗时操作可能发生ANR,IntentService会创建一个工作线程来处理多线程任务;
  • Service长期存在后台,结束需要主动调用stopSelft()来结束服务,而IntentService会在任务完成后默认调用stopSelft()直接退出;
  • 两者都可以是使用startService()启动,但IntentService不能onBind();

使用场景

IntentService适合多个任务需要按顺序,适用更高优先级的的后台任务,不容易被系统杀死的使用场景,比如离线下载场景,后台下载场景。

Powered by Hexo & Theme Keep
Unique Visitor Page View