IntentService是继承与Service的。所以IntentService也是一个Service,拥有Service的所有特性。
public abstract class IntentService extends Service
IntentService相比于Service有什么区别呢?IntentService可以执行一些耗时任务,并且任务完成后会服务会自动销毁。具体的源码分析如下:
//IntentService onCreate()方法
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
可以看出来在IntentService的onCreate()方法中创建了HandlerThread,并且开启了这个线程,然后创建了一个Handler对象,绑定HandlerThread的Looper对象,由此可知,IntentService异步任务的原理在HandlerThread+Handler。下面在看下onStart()方法:
//IntentService onStart()方法
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看到每次开启IntentService,会调用onStart()方法,每次的意图Intent都会包装为一个Message,然后通过Handler发送到HandlerThread内部的消息队列中,并且熟悉HandlerThread的都知道其内部是构建了一个Looper的环境的。所以可以得出,IntentSerivce对于任务是顺序处理的,因为任务都会存放在HandlerThread的消息队列中,所以IntentService其实是一个单线程+消息队列的模式。那么IntentService是如何处理任务的呢?,看如下源码:
//IntentService 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);
}
}
//IntentService onHandleIntent()
protected abstract void onHandleIntent(@Nullable Intent intent);
可以看出每次开启IntentService,任务会被封装成一个Message,然后有Handler发送到HandlerThread的消息队列中,最终会消息对的处理会回调onHandleIntent这个抽象方法,所以需要我们重写此方法,在此方法里执行我们的耗时任务操作。那么可以注意到onHandleIntent()方法调用后会调用stopSelf()方法,那么stopSelf()的机制是怎么样的呢?
public final void stopSelf(int startId) {
if (mActivityManager == null) {
return;
}
try {
mActivityManager.stopServiceToken(
new ComponentName(this, mClassName), mToken, startId);
} catch (RemoteException ex) {
}
}
可以看到执行了mActivityManager.stopServiceToken(
new ComponentName(this, mClassName), mToken, startId);这个方法
那么并且传递了startId这个标识,每次启动IntentService都会生成这一个标识,作为一个记录。最终会调用到ActiveServices stopServiceTokenLocked(ComponentName className, IBinder token,
int startId)方法
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
int startId) {
if (r != null) {
if (startId >= 0) {
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
while (r.deliveredStarts.size() > 0) {
ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}
}
if (r.getLastStartId() != startId) {
return false;
}
if (r.deliveredStarts.size() > 0) {
Slog.w(TAG, "stopServiceToken startId " + startId
+ " is last, but have " + r.deliveredStarts.size()
+ " remaining args");
}
}
synchronized (r.stats.getBatteryStats()) {
r.stats.stopRunningLocked();
}
r.startRequested = false;
if (r.tracker != null) {
r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
}
r.callStart = false;
final long origId = Binder.clearCallingIdentity();
bringDownServiceIfNeededLocked(r, false, false);
Binder.restoreCallingIdentity(origId);
return true;
}
return false;
}
我们可以看到最关键的if (r.getLastStartId() != startId)不是最后一个startId就直接return false。否则将执行 r.stats.stopRunningLocked();来终止。自此这个问题终于真相大白了。
//HandlerThread onDestroy()方法
public void onDestroy() {
mServiceLooper.quit();
}
并且IntentService停止后会调用onDestroy()生命周期方法,内部终止了HandlerThread内部的loop循环,进而使得HandlerThread也随之结束。
根据以上的分析,可以得知IntentService可以用来处理耗时的后台任务,相比我们新开一个线程,它在任务完成时会主动关闭,且内部处理任务是顺序执行的,多次开启IntentService,任务会在队列中排队,依次被执行。且IntentService是服务的特性,可以相应的提高进程优先级。