IntentService
是Service
的子类,由于Service
中不能进行耗时操作。因此google提供了一个IntentService
,内部维护了一个子线程来进行操作,且当任务完成后,Service会自动销毁。当有多个任务来临时,其会依次按序执行。那么IntentService
如何实现的呢?
IntentService 的使用
class IntentServiceTest extends IntentService {
public IntentServiceTest() {
super("IntentServiceTest");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//此处取出 intent数据,进行处理
}
}
复制代码
IntentService
的使用很简单,只要实现onHandleIntent
方法就可以,在方法内进行操作,onHandleIntent
方法就在子线程内。IntentService
有个setIntentRedelivery(boolean enabled)
方法,当传入值为 true
时,如有任务还没完成情况下,Service
却被杀死,那么在内存充足时,服务会被重启,且 最后传入的任务将会被重新执行。而传入flase,则未完成任务不会被重新执行。
注意:当有多个未完成任务时,只有最后一个传入的任务会被执行。
接下分析下IntentService
的实现。
InetentService源码分析
先来看看IntentService
的onCreate
方法。
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
复制代码
当IntentService
被创建时,就初始化了一个HandlerThread
线程,创建了一个ServiceHandler
.任务将会被传入 mServiceHandler
执行。
接下来,看下任务如何被执行的。
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);
}
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
复制代码
当调用startService
时,将走到onStartCommad
, 在onStartCommad
方法中调用onStart
方法。传入intent
和 startId
. onStart
创建Message
将intent
和startId
作为obj
和参数传入。handleMessage
中先调用 onHandleIntent
方法,onhandleIntent
中完成要对数据进行的处理,任务完成后,就调用stopSelf
方法去销毁服务,在onDestroy
会将handle
线程销毁。
可能有同学会有疑问,stopSelf
方法调用停止服务,那么多个任务来临时,后面的任务岂不是不会被执行了?这当然是不可能的。stopSelf
方法调用时传入了一个startId
,这个startId
是在每次startService时都会往onStartCommand
传入一个新值。调用stopSelf
,如果传入的是一个大于0的值,会判断该值是否等于最后一次传入的 startId,如果是最后一个Service
会走到onDestory流程
,如果不是则Service
仍然存活。
stopSelf
流程如下:
Service.java#stopSelf->ActivityManagerService.java#stopServiceToken->ActiveServices.java#stopServiceTokenLocked
boolean stopServiceTokenLocked(ComponentName className, IBinder token,
int startId) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className
+ " " + token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
if (r != null) {
if (startId >= 0) {
// Asked to only stop if done with all work. Note that
// to avoid leaks, we will take this as dropping all
// start items up to and including this one.
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false);
if (si != null) {
while (r.deliveredStarts.size() > 0) {
ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}
}
//代码1
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;
}
复制代码
- 代码1处可以看到如果 startId不是最后一个,就会直接返回false,不走 停止服务的流程。
接下来再来分析下 setIntentRedelivery
传入 true
时,为何最后一个任务(如果任务未完成)就会被执行,其他未完成任务为何不会被重新执行。
setIntentRedelivery方法分析
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
复制代码
如上代码,当 setIntentRedelivery
传入为 true
时,onStartCommand
会返回 START_REDELIVER_INTENT
,在该返回值下,服务被杀死后,在满足一定条件下,服务会被系统重新创建,且重新创建后,直接将之前Intent的值传入。
因此只有最后一个传入的任务才会被重新执行。