Android中线程形态AsyncTask、HandlerThread和IntentService工作原理分析

《Android中线程形态AsyncTask、HandlerThread和IntentService简介》中,我们介绍了在Android中扮演线程角色的AsyncTask、HandlerThread和IntentService的基本使用以及示例。接下来我们将通过一些关键的源码来继续往下探索它们的工作原理。

AsyncTask的工作原理

之前,我们在简介篇中提到,从Android3.0开始,为了避免AsyncTask所带来的并发错误,AsyncTask采用了一个线程来串行执行任务,但仍然可以通过AsyncTask的executeOnExecutor方法来并行执行任务。所以,我们便要从AsyncTask的execute方法和executeOnExecutor方法源码看起。

public final AsyncTask<Params, Progress,Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
……
public final AsyncTask<Params, Progress,Result> executeOnExecutor(Executor exec, Params... params) {
    if (mStatus!= Status.PENDING) {
        switch(mStatus) {
           case RUNNING:
                throw newIllegalStateException("Cannot execute task:"
                        + " the task isalready running.");
           case FINISHED:
               throw new IllegalStateException("Cannot execute task:"
                        + " the task hasalready been executed "
                        + "(a task can beexecuted only once)");
        }
    }
    mStatus =Status.RUNNING;
    onPreExecute();
    mWorker.mParams = params;
    exec.execute(mFuture);
    return this;
}

可以看到,execute方法最后还是调用了executeOnExecutor方法,它在参数中传入了一个静态对象sDefaultExecutor。那我们接着来看看sDefaultExecutor是一个什么对象,源码:

/**
 * An {@linkExecutor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particularprocess.
 */
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
……
private static volatile Executor sDefaultExecutor =SERIAL_EXECUTOR;
……
private static class SerialExecutor implements Executor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;
    public synchronized void execute(final Runnable r) {
       mTasks.offer(new Runnable() {
           public void run() {
               try {
                   r.run();
               } finally {
                   scheduleNext();
               }
            }
        });
        if(mActive == null) {
           scheduleNext();
        }
    }
    protected synchronized void scheduleNext() {
        if((mActive = mTasks.poll()) != null) {
           THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

从上面可以看到,sDefaultExecutor就是SERIAL_EXECUTOR,而SERIAL_EXECUTOR是一个内部类SerialExecutor的对象,而内部类SerialExecutor实现了线程池接口Executor,并重写execute方法,所以它是一个线程池,准确来说它应该是一个任务执行器,而且它是一个串行的任务执行器。因为execute方法中有一个队列对象mTasks,如果这时没有正在活动的AsyncTask任务,那么就会调用scheduleNext方法来执行下一个AsyncTask任务。同时当一个AsyncTask任务执行完后,AsyncTask会继续执行其他任务直到所有任务都被执行为止,所以在默认情况下,AsyncTask是串行执行的。

scheduleNext方法里执行任务的是THREAD_POOL_EXECUTOR,它是真正执行任务的线程池

/**
 * An {@linkExecutor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR = 
new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

了解了sDefaultExecutor和THREAD_POOL_EXECUTOR两个线程池的所在意义后,我们继续再看回executeOnExecutor方法,所以如果想AsyncTask并行执行任务,第一个参数就得传入THREAD_POOL_EXECUTOR。

executeOnExecutor方法里exec.execute(mFuture);是执行任务代码,在它之前可以看到有方法onPreExecute();,我们在上一节介绍到,这个是四个重要的回调方法的第一个,它在主线程中执行,在异步任务执行之前的回调,一般用于做一些准备工作。再看回exec.execute(mFuture);,参数mFuturem是一个FutureTask并发类的对象交给execute方法去处理,如果调用的是execute方法,那么就会交由SerialExecutor的execute方法去,会把它插入到任务队列mTasks中,如果调用的是executeOnExecutor方法,则会交由THREAD_POOL_EXECUTOR线程池的execute方法去处理。

说到这里,大家应该都明白AsyncTask的为什么默认是串行执行和怎样使用并行执行的原理了吧。接下来,我们继续探索一下doInBackground方法的工作原理,以便进一步揭开doInBackground、publishProgress、isCancelled、onProgressUpdate、onPostExecute和onCancelled的关系。继续看回上面executeOnExecutor方法,在执行onPreExecute();第一个回调后,有mWorker.mParams = params;,这是把传入的传数赋值给mWorker对象的mParams,那么mWorker对象是什么呢,它为什么要接收mParams参数呢,和到最后mParams是怎样走到doInBackground方法去的呢?只要看下AsyncTask的构造函数便一清二楚了:

/**
 * Creates anew asynchronous task. This constructor must be invoked on the UI thread.
 */
public AsyncTask() {
    mWorker = new WorkerRunnable<Params, Result>() {
        publicResult call() throws Exception {
           mTaskInvoked.set(true);
           Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
           //noinspection unchecked
           Result result = doInBackground(mParams);
           Binder.flushPendingCommands();
           return postResult(result);
        }
    };
    mFuture = new FutureTask<Result>(mWorker) {
       @Override
       protected void done() {
            try {
               postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
               android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
               throw new RuntimeException("An error occurred while executingdoInBackground()", e.getCause());
            } catch (CancellationException e) {
               postResultIfNotInvoked(null);
            }
        }
    };
}

mWorker是内部抽象类WorkerRunnable对象,该类实现接口Callable,所以它是一个任务对象传给了mFuture并发类的对象。可以看到mWorker重写call方法体中有我们熟悉的doInBackground方法,而mParams便就是给doInBackground传递的,所以doInBackground所接收的参数便是我们开启任务调用execute里的参数。

doInBackground方法执行结束后,返回结果调用return postResult(result);,继续看postResult方法源码和前面提到更新进度的publishProgress方法源码,它们都是往Handler发送消息,InternalHandler类用于将执行环境从线程池切换到主线程,它在接收到消息后分别调用finish方法和onProgressUpdate方法:

private Result postResult(Result result) {
   @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            newAsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}
……
/**
 * This methodcan be invoked from {@link #doInBackground} to
 * publishupdates on the UI thread while the background computation is
 * stillrunning. Each call to this method will trigger the execution of
 * {@link#onProgressUpdate} on the UI thread.
 *
 * {@link#onProgressUpdate} will not be called if the task has been
 * canceled.
 *
 * @paramvalues The progress values to update the UI with.
 *
 * @see#onProgressUpdate
 * @see#doInBackground
 */
@WorkerThread
protected final void publishProgress(Progress...values) {
    if(!isCancelled()) {
       getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
               new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}
……
private static class InternalHandler extends Handler{
    publicInternalHandler() {
       super(Looper.getMainLooper());
    }
   @SuppressWarnings({"unchecked","RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
       AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch(msg.what) {
           case MESSAGE_POST_RESULT:
               // There is only one result
               result.mTask.finish(result.mData[0]);
               break;
           case MESSAGE_POST_PROGRESS:
               result.mTask.onProgressUpdate(result.mData);
               break;
        }
    }
}
……
private void finish(Result result) {
    if(isCancelled()) {
       onCancelled(result);
    } else {
       onPostExecute(result);
    }
    mStatus =Status.FINISHED;
}

先来说下onProgressUpdate方法,此方法便是四个重要的回调方法的第二个:在主线程中执行,在异步任务执行中进度发生改变时的回调,一般用于做进度的更新。然后看下finish方法的实现,它通过isCancelled()判断是否取消停止执行还是正常执行结束来对应回调四个重要的回调方法的第三个和第四个:onPostExecute(Resultresult)在主线程中执行,在异步任务正常执行完后之后被回调,一般用于做界面完成的更新;onCancelled()在主线程中执行,在异步任务被取消后执行完后的回调,一般用于做界面取消的更新。

好了,分析到这里,相信大家应该都清楚了AsyncTask的工作原理了,剩下的细节代码大家可以自行查看源码了解。

HandlerThread的工作原理

我们在简介篇中提到,HandlerThread本质上就是具有消息循环的Thread,具有消息循环就是此线程存在Looper,所以我们从HandlerThread的run方法说起,请看源码:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper= Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()方法开启消息循环。HandlerThread原理相对Thread来讲还算比较简单的,只要理解Looper就可以,关于Looper的内容,我们后面专门来讲解。最后别忘了,当明确不需要再使用HandlerThread时,应该通过它的quit或quitSafely方法来终止线程的执行。quit会清空消息池中所有的消息,而quitSafely只会清空消息池中延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理。(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)

IntentService的工作原理

我们在简介篇中提到,IntentService内部采用了HandlerThread来执行任务,当任务执行完毕后IntentService会自动退出。我们来看看它的onCreate方法:

@Override
public void onCreate() {
    // TODO: Itwould be nice to have an option to hold a partial wakelock
    // duringprocessing, and to have a static startService(Context, Intent)
    // methodthat would launch the service & hand off a wakelock.
   super.onCreate();
   HandlerThread thread = new HandlerThread("IntentService[" +mName + "]");
   thread.start();
   mServiceLooper = thread.getLooper();
   mServiceHandler = new ServiceHandler(mServiceLooper);
}

onCreate方法是Service第一次启动时被调用,IntentService也是Service,所以也不例外。从上面源码看到,在onCreate方法中创建了一个HandlerThread对象,然后获取Looper对象赋予mServiceLooper,再通过此Looper构造一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终都会在HandlerThread执行。

每一次启动Service,它的onStartCommand方法都会被调用一次,而Service源码中可看到onStartCommand方法是调用了onStart方法的,所以我们再来看看IntentService的onStart方法源码:

@Override
public void onStart(Intent intent, int startId) {
    Message msg= mServiceHandler.obtainMessage();
    msg.arg1 =startId;
    msg.obj =intent;
    mServiceHandler.sendMessage(msg);
}

可以看到此方法中只是很简单地往mServiceHandler中发送一条消息,这消息会在HandlerThread中被处理,上面提到mServiceHandler就是Handler对象,mServiceHandler对象其实是内部类ServiceHandler对象,我们再来看看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);
    }
}

Handler收到消息后,会将Intent对象传递给onHandlIntent方法去处理,onHandlIntent是抽象方法,必须得在子类中去实现,这个我们在简介篇中有介绍过。当onHandleIntent方法执行完毕后会通过stopSelf方法来尝试停止服务。一般来说stopSelf()无参数情况下会立即停止服务,而stopSelf(int startId)会尝试停止之前会判断最近启动服务的次数是否和startId相等,如果相等才立即停止服务。

由于每执行一个后台任务就必须启动一次IntentService,而IntentService内部则通过消息的方式向HandlerThread请求执行任务,Handler中的Looper是顺序处理消息的,所以当有多个后台任务同时存在时,这些后台任务会按照发起的顺序排队执行。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值