IntentService
是一种特殊的 Service,它继承了 Service 并且它是一个抽象类,因此必须创建它的子类才能使用 IntentService
。IntentService
可用于执行后台耗时任务,当任务执行后它会自动停止,同时由于 IntentService
是服务的原因,这导致它的优先级比单纯的线程要高很多,所有 IntentService
比较适合执行一些高优先级的后台任务,因为它优先级高不容易被系统杀死。
在实现上,IntentService
封装了 HandlerThread
和 Handler,这一点可以从它的 onCreate
方法中看出来,如下所示。
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 = thead.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
当 IntentService
被第一次启动时,它的 onCreate
方法会被调用,onCreate
方法会创建一个 HandlerThread
,然后使用它的 Looper 来构造一个 Handler 对象 mServiceHandler
,这样通过 mServiceHandler
发送的消息最终都会在 HandlerThread
中执行,从这个角度来看, IntentService
也可以用于执行后台任务。每次启动 IntentService
, 它的 onStartCommand
方法就会调用一次,IntentService
在 onStartCommand
中处理每个后台任务的 Intent。
下面看一下 onStartCommand
方法是如何处理外界的 Intent 的,onStartCommand
调用了onStart,onStart 方法的实现如下所示。
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
方法去处理。注意这个 Intent 对象的内容和外界的 startService(intent)
中的 intent 的内容是完全一致的,通过这个 Intent 对象的内容即可解析出外界启动 IntentService
时所传递的参数,通过这些参数就可以区分具体的后台任务,这样在 onHandleIntent
方法中就可以对不同的后台任务做处理了。
当 onHandleIntent
方法执行结束后,IntentService
会通过 stopSelf(int startId)
方法来尝试停止服务。这里之所以采用 stopSelf(int startId)
而不是 stopSelf()
来停止服务,那是因为 stopSelf()
会立刻停止服务,而这个时候可能还有其他消息未处理,stopSelf(int startId)
则会等待所有的消息都处理完毕后才终止服务。一般来说,stopSelf(int startId)
在尝试服务之前会判断最近启动服务的次数是否和 startId 相等,如果相等就立刻停止服务,不相等则不停止服务,这个策略可以从 AMS 的 stopServiceToken
方法的实现中找到依据,读者感兴趣的话可以自行查看源码实现。ServiceHandler
的实现如下所示。
private final class ServiceHandler extends Handler {
public ServiceHandler (Looper looper) {
super (looper);
}
@Override
public void handlerMessage (Message msg) {
onHandlerIntent ((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
IntentService
的 onHandleIntent
方法是一个抽象方法,它需要我们在子类中实现,它的作用是从 Intent 参数中区分具体的任务并执行这些任务。如果目前只存在一个后台任务,那么 onHandleIntent
方法执行完这个任务后,stopSelf(int startId)
就会直接停止服务;如果目前存在多个后台任务,那么当 onHandleIntent
方法执行完最后一个任务时,stopSelf(int startId)
才会直接停止服务。另外由于每执行一个后台任务就必须启动一次 IntentService
,而 IntentService
内部则通过消息的方式向 HandlerThread
请求执行任务,Handler 中的 Looper 是顺序处理消息的,这就意味着 IntentService
也是顺序执行后台任务的,当有个多个后台任务同时存在时,这些后台任务会按外界发起的顺序排队执行。
下面通过一个示例来进一步说明 IntentService
的工作方式,首先派生一个 IntentService
的子类,比如 LocalIntentService
,它的实现如下所示。
public class LocalIntentService extends IntentService {
public static final String TAG = ""LocalIntentService;
public LocalIntentService () {
super (TAG);
}
@Override
protected void onHandleIntent (Intent intent) {
String action = intent.getStringExtra ("task_action");
Log.d (TAG, "receive task :" + action);
SystemClock.sleep (3000);
if ("com.ryg.action.TASK1".equals (action)) {
Log.d (TAG, "handle task: " + action);
}
}
@Override
public void onDestory () {
Lod.d (TAG, "service destroyed");
super.onDestroy();
}
}
这里对 LocalIntentService
的实现做一下简单的说明。在 onHandleIntent
方法中会从参数中解析出后台任务的标识,即 task_action
字段所代表的内容,然后根据不同的任务标识来执行具体的后台任务。这里为了安全起见,直接通过 SystemClock.sleep(3000)
来休眠 3000 毫秒从而模拟一种耗时的后台任务,另外为了验证 IntentService
的停止时机,这里在 onDestroy
中打印了一句日志。LocalIntentService
实现完成了以后,就可以在外界请求执行后台任务了,在下面的代码中先后发起了3个后台任务的请求:
Intent service = new Intent (this, LocalIntentService.class);
service.putExtra ("task_action", "com.ryg.action.TASK1");
startService (service);
service.putExtra ("task_action", "com.ryg.action.TASK2");
startService (service);
service.putExtra ("task_action", "com.ryg.action.TASK3");
startService (service);
运行程序,观察日志,如下所示。
05-17 17:08:23.186 E/dalvikvm (25793):threadid=11:calling run(), name=IntentService[LocalIntentService]
05-17 17:08:23.196 D/LocalIntentService(25793):receive task:com.ryg.action.TASK1
05-17 17:08:26.199 D/LocalIntentService(25793):handle task:com.ryg.action.TASK1
05-17 17:08:26.199 D/LocalIntentService(25793):receive task:com.ryg.action.TASK2
05-17 17:08:29.192 D/LocalIntentService(25793):receive task:com.ryg.action.TASK3.
05-17 17:08:32.205 D/LocalIntentService(25793):service destroyed.
05-17 17:08:32.205 E/dalvikvm(25793):threadid=11:exiting, name=IntentService[LocalIntentService]
从上面的日志可以看出,三个后台任务是排队执行的,它们的执行顺序就是他们发起请求对的顺序,即 TASK1、TASK2、TASK3。另外一点就是当 TASK3 执行完毕后,LocalIntentService
才真正地停止,从日志中可以看出 LocalIntentService
执行了 onDestroy()
,这也意味着服务正在停止。
完~
喜欢有帮助的话: 双击、评论、转发,动一动你的小手让更多的人知道!关注 Android_YangKe