Android中的IntentService解析

IntentService简介

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,任务会在队列中排队,依次被执行。且IntentService是服务的特性,可以相应的提高进程优先级。

你可能感兴趣的:(Android)