在Android开发中,我们通常会把耗时操作放到Service中处理,但是由于Service也是运行在主线程中的,所以在Service中直接处理耗时操作也是会导致ANR的。所以,我们一般需要在Service中另起线程去处理耗时操作。Android为我们提供了简单的机制去实现在Service中创建线程处理耗时任务,它就是IntentService。
IntentService继承自Service,它内部封装了一个HandleThread去实现异步任务处理。通过startService提交任务,所有的任务串行执行,当所有任务都处理掉完毕后,service会自动停止,并不需要显示调用stopService。
IntentService的使用
IntentService的使用需要创建一个子类去继承IntentService,并实现里面的抽象方法 onHandleIntent,在onHandleIntent方法中去处理耗时操作,下面我们来看一下IntentService的大致实现:
public class TestIntentService extends IntentService {
public TestIntentService(String name) {
super(name);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(Intent intent) {
//do something
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
使用IntentService我们不需要去创建线程去执行耗时任务,因为它的内部已经封装了一个HandleThread,它是一个带有Loop的thread,使用它可以轻松的去执行耗时的异步任务。同时,我们也不必去关心停止service的操作,因为IntentService默认会在所有任务处理完毕后去主动停止Service。下面我们从源码的角度来分析下IntentService的具体实现,这样就能更加清晰的了解IntentService所具有的特点。
IntentService的源码实现
下面我们来看一下IntentService的源码实现:
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);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* 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(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
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)}.
*/
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
从onStartCommand和onHandleIntent方法的注释中,我们就很清楚的知道IntentService的使用,及其所具有的特性。下面我们来一步步来看这是如何实现的。
IntentService本身也是一个Service,它具有Service的生命周期。我们先来看一下onCreate方法的实现,在onCreate方法中,创建一个HandleThread对象thread,这个thread将被用来执行耗时操作。同时用thread的Looper对象初始化了一个ServiceHandler对象mServiceHandler。ServiceHandler是IntentService的内部类,它继承自Handler,后面用到的时候我们再来分析它。至此,我们知道onCreate方法里就做了两件事,创建了一个HandleThread,以及和它关联的Handler对象。
根据Service的生命周期,当有startService调用时,会回调onStartCommand方法。我们来看下onStartCommand方法的实现:
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
onStartCommand方法里面的逻辑很简单,在这个里面调用了onStart方法,它的返回值根据IntentService的成员变量mRedelivery 的值有两种情况,当mRedelivery 为true时返回START_REDELIVER_INTENT ,为false时返回的是START_NOT_STICKY。熟悉Service的同学应该知道,onStartCommand方法的返回值决定了当Service被系统kill掉的时候,service能否被自动重新创建。START_REDELIVER_INTENT 表明系统会自动重新创建该service,并会再次发送被kill之前的最后一个intent。START_NOT_STICKY表面系统不会自动重新创建该service。
在IntentService中,mRedelivery 的默认值是false。它同时也提供了接口函数去改变mRedelivery 变量的值,这个方法就是setIntentRedelivery。前面我们提到了onStartCommand方法里面直接调用了onStart方法,下面我们来看下onStart方法:
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
从代码可以看到,onStart方法的逻辑也很简单,就是通过我们在onCreate里面初始化的mServiceHandler去发送了一条消息。我们来看下ServiceHandler 的定义:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
我们知道mServiceHandler发送的消息会交给Handler的handleMessage去处理,而handleMessage会运行在handler looper所在的线程。在IntentService中,mServiceHandler的looper是在HnadlerThread中的,所以这个handleMessage会运行在HnadlerThread的线程中,这样就做到了IntentService去处理耗时操作而不用担心会阻塞主线程。
在handleMessage中调用了onHandleIntent以及stopSelf方法,所以我们只需要把耗时操作写在onHandleIntent中去就可以了。同时,它自动调用了stopSelf方法,并传入对应的start id,这就解释了IntentService不需要我们手动显示调用stop方法,它会在处理完所有的intent之后自动停止。
至此,我们就了解了IntentService的使用以及内在实现机制。它适用于处理串行耗时操作,对于需要并行处理的操作,就需要自己在Service里面创建和管理线程。