概述
IntentService 是一个特殊的 Service,它继承了 Service 并且是一个抽象类,因此必须创建它的子类才能使用 IntentService。一般我们用 Service 在后台做一些耗时操作。这个时候我们需要在 Service 中开启子线程,也要管理 Service 的生命周期。IntentService 这个类的存在就是为了简化我们这些操作的。使用这个类,我们不需要自己去创建子线程,不需要手动管理 Service 的生命周期。
使用
我们用一个简单的例子看一下 IntentService 的使用方式。定义一个 IntentService 的子类 LocalIntentService:
public class LocalIntentService extends IntentService {
private static final String TAG = "LocalIntentService";
public static final String TASK_ACTION = "task_action";
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 ("cc.action.TASK1".equals(action)) {
Log.d(TAG,"handle task : " + action);
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG,"service destroyed");
}
}
当我们继承 IntentService 的时候,我们必须重写 onHandleInten 方法,在这里我们会接收到起服务的 intent,在这里处理 intent。我们在这个方法里让线程休眠3秒模拟一个耗时操作。然后,我们在外界请求执行后台任务:
private void localService() {
Intent intent = new Intent(this,LocalIntentService.class);
intent.putExtra(LocalIntentService.TASK_ACTION,"cc.action.TASK1");
startService(intent);
Intent intent2 = new Intent(this,LocalIntentService.class);
intent2.putExtra(LocalIntentService.TASK_ACTION,"cc.action.TASK2");
startService(intent2);
Intent intent3 = new Intent(this,LocalIntentService.class);
intent3.putExtra(LocalIntentService.TASK_ACTION,"cc.action.TASK3");
startService(intent3);
}
我们打印了收到任务的日志,task1处理的日志,最后打印了 Service 销毁的日志。我们看一下运行日志:
03-23 11:37:34.867 8178-8363/cc.handlerdemo D/LocalIntentService: receive task : cc.action.TASK1
03-23 11:37:37.869 8178-8363/cc.handlerdemo D/LocalIntentService: handle task : cc.action.TASK1
03-23 11:37:37.870 8178-8363/cc.handlerdemo D/LocalIntentService: receive task : cc.action.TASK2
03-23 11:37:40.872 8178-8363/cc.handlerdemo D/LocalIntentService: receive task : cc.action.TASK3
03-23 11:37:43.876 8178-8178/cc.handlerdemo D/LocalIntentService: service destroyed
从日志可以看出,三个任务是排队执行的,他们的执行顺序是和他们的发起顺序是一致的。当三个任务都执行完后才执行 onDestroy 方法。知道了它的用法之后,我们看看它的源码,理清它的实现原理。
源码分析
首先,看一下它的 onCreate 方法:
@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 + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
看到这里,我们心里应该有了一个大概。onCreate 方法里面出现了 HandlerThread 和 Handler。所以,IntentService 内部是封装了 HandlerThread 和 Handler。接着看一下 onStartCommand 方法:
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
直接调用的 onStart 方法:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
onStart 方法就做了一件事:发送一个消息。这个消息里面就包含了我们起服务发送的 intent。然后这个消息会发送给 HandlerThread 去处理:
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);
}
}
handleMessage 方法调用了我们要实现的方法:onHandleIntent。这样我们的任务就到了子线程去处理,不需要我们new Thread 去处理我们的耗时操作,满足了我们的第一点。接着,onHandleIntent 方法执行完后会执行 stopSelf(int startId) 方法来尝试停止服务。为什么不直接使用 stopSelf()方法呢?因为调用 stopSelf()会立刻停止服务,而这个时候可能还有消息没有处理,stopSelf(int startId)则会等待所有消息都处理完毕才会终止服务。在尝试停止服务的时候会判断最近启动服务的次数是否和 startId 相等。如果相等就停止服务,否则不停止。