IntentService 详解

1,547 阅读3分钟

IntentServiceService的子类,由于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源码分析

先来看看IntentServiceonCreate 方法。

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方法。传入intentstartId. onStart创建MessageintentstartId作为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的值传入。 因此只有最后一个传入的任务才会被重新执行。