在说IntentService 之前我们先来了解下Service,Service 是长期运行在后台的应用程序组件。Service 不是一个单独的进程,它和应用程序在同一个进程中,它也不是一个线程,它和线程没有半毛钱关系,所以它不能处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR。如果有耗时操作就必须开启一个单独的线程来处理。
IntentService是继承于 Service 并处理异步请求的一个类。在他的内部有一个工作线程来处理耗时操作,启动 IntentService的方式和启动传统Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。而且,所有请求都在一个子线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。
源码分析
IntentService的源码代码量不大,逻辑也很简单:
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
@UnsupportedAppUsage
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
//这里自定义一个Handler,他是在IntentService的onCreate方法里面完成初始化的,主要两个
//作用:一是在在完成初始化之后的onstart()方法里面获取到Message对象,方便后面处理结果的
//发送,二是在任务完成后将任务结果信息发送出去,也就是调用onHandleIntent方法;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override public void handleMessage(Message msg) {
//调用onHandleIntent方法将任务结果信息发送出去,该方法工作在工作线程
onHandleIntent((Intent)msg.obj);
//onHandleIntent 处理完成后 IntentService会调用 stopSelf() 自动停止。
stopSelf(msg.arg1)
}
}
public IntentService(String name) {
super();
mName = name;
}
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override public void onCreate() {
super.onCreate();
//这里通过HandlerThread对象巧妙地获取到主线程的Looper对象,用于Handler通信,
//并维护自己的工作队列;从这里我们可以知道,IntentService至少是Intent+Service
//+Handler+Thread组成的一个复杂的具有处理异步任务兼备通信的综合体。
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override public void onStart(@Nullable Intent intent, int startId) {
//在这里通过mServiceHandler对象获取到主线程里面的Message对象
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//这里IntentService通过Handler发生任务(消息)到MessageQueue队列去,然后通过
//onHandleIntent()去执行。
mServiceHandler.sendMessage(msg);
}
//通过onStartCommand()调用onStart()方法把工作任务传递给服务intent,依次插入到工作队列
//中,并逐个发送给onHandleIntent()
@Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
//调用onStart()方法开始处理任务,因此多次启动 IntentService 不会重新创建新的服务
//和新的线程,只是把消息加入消息队列中等待执行,
//而如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override public void onDestroy() {
mServiceLooper.quit();
}
@Override @Nullable
public IBinder onBind(Intent intent) {
return null;
}
//根据注解,我们可以知道这个方法是在工作线程也就是子线程里面执行的。
//我门在使用IntentService的时候,这个方法是我们唯一必须实现并重写的一个方法。我们的异步任
//务逻辑就写在这里,然后将结果通过广播或者EventBus发送出去。
//当然我们也可以自定义自定义一个IntentService,在里面添加实现逻辑所需要的参数和方法,但对异
//步任务的处理方式都大同小异
@WorkerThread protected abstract void onHandleIntent(@Nullable Intent intent);
}
使用bindService启动IntentService的时候要注意,在该模式下,IntentService执行完耗时操作后不会自动的调用onDestroy()方法自行销毁,这个时候我们需要自己手动调用unbindService()方法解绑并销毁它,以防意外出现而不能销毁服务。
IntentService为什么只能用StartService来开启服务?
因为传递的intent最后都会封装成message由serviceHandler发送到消息队列,而serviceHandler发送的过程是在onStartCommand中完成的,而只有startService方法启动的Service才会执行onStartCommand()方法。