Android多线程机制 【Android中的多线程】由于讨论的主要是Android中特有的线程机制和类,因此在此不会再详谈Java中的线程类Thread和Runnable。
Android中可以扮演线程的角色有很多,AsyncTask、IntentService和HandlerThread,AsyncTask的底层实际上就是一个线程池,IntentService的底层实际上就是HandlerThread和Handler,而HandlerThread底层实际上就是Android的消息机制和Thread的组合。
Android中的线程形态
AsyncTask
AsyncTask是一个抽象的泛型类:
public abstract class AsyncTask
AsyncTask的具体使用在这里就不再讨论,我们主要了解其工作原理。
AsyncTask的工作原理 在使用AsyncTask时我们最终都要调用它的execute(Params… params)方法,因此我们从execute方法开始。
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
可以看到execute方法内部调用了executeOnExecutor方法,sDefaultExecutor是一个串行的线程池,一个进程中所有的AsyncTask都在这个线程池中排队执行,这个过程之后再分析,我们先来看看executeOnExecutor方法到底做了些什么事:
public final AsyncTask executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
在executeOnExecutor()方法中,首先执行了我们在创建AsyncTask对象时重写的onPreExecute()方法,这个方法大家都很熟悉,就是在执行任务前的准备工作,是一个在主线程中执行的方法。接着将参数构造AsyncTask时传入的参数Params包装成FutureTask对象,在Java中FutureTask就是Runnable的升级版,在这里我们把他当做Runnable就行,最后我们将这个FutureTask交给了线程池去执行。于是我们接着来到这个串行线程池类——SerialExecutor的内部:
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
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);
}
}
}
在SerialExecutor内部的execute方法中,首先将FutureTask加入到了任务队列mTasks中,如果这时候没有活跃的AsyncTask任务的话,就调用scheduleNext()方法执行下一个AsyncTask任务,并且我们发现execute并不是执行线程任务的方法,真正执行执行任务的方法是scheduleNext(),这个方法将AsyncTask任务又转交给了另一个线程池THREAD_POOL_EXECUTOR去执行,所以AsyncTask底层实际上是利用到了两个线程池:SerialExecutor和THREAD_POOL_EXECUTOR,前者的内部主要是一个任务队列,它取出一个任务就将其交给THREAD_POOL_EXECUTOR去处理。
HandlerThread
HandlerThread是一种使用了Handler消息机制的Thread,它的具体实现非常简单,就是在run方法中通过
Looper.prepare()
创建了一个消息队列,并通过Looper.loop()
开启消息循环,有了Looper的话就可以在实际使用中创建Handler了。@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
由于HandlerThread内部实现实际上是Android消息机制,因此我们要使用HandlerThread时只需要拿到它的Handler并用Handler发送消息即可,我们接着要讲的IntentService内部实现正好就是HandlerThread。
IntentService
IntentService是一种特殊的Service,在IntentService中执行的任务会默认放在子线程中执行,并且由于IntentService继承了Service,是四大组件之一,因此其优先级非常高,比一般的线程更难被系统杀死,因此我们可以将一些非常重要的耗时操作交给IntentService处理。
在启动一个IntentService之前首先会调用onCreate方法:
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
可以看到在IntentService的onCreate方法中,首先创建了一个HandlerThread并且让其启动,接着获取到HandlerThread的Looper,并通过Looper获取到了HandlerThread的Handler(这里是特殊的ServiceHandler),有了这个Handler就可以通过消息机制将耗时任务交给HandlerThread处理了。
在每次启动服务的时候系统都会回调onStartCommand()方法:
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
我们发现onStartCommand内部实际上调用的是onStart方法将外部Intent交给了onStart方法处理,于是我们回到onStart():
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
在onStart内部就很简单了,首先得到一个Message,并将intent和id放入Message,通过之前得到的Handler发送将这条消息发送出去就可以了。这里的Intent就是我们外界在startService(intent)时传入的Intent,通过这个Intent就可以解析出外界启动IntentService时传递的参数,通过这些参数就可以区分后台具体要执行什么任务了。
这里我们又会觉得奇怪了,既然我们将消息交给Handler处理了,可是我们之前在学习HandlerThread的时候,发现HandlerThread内部实际上只创建了一个Looper,我们并没有在其中派生Handler的子类并重写handleMessgae()方法,那么到底在哪里处理了消息呢?这里我们需要注意到这里的Handler是ServiceHandler,ServiceHandler是Handler的子类,在ServiceHandler的内部已经帮我们重写了handleMessage()方法:
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);
}
}
没错,ServiceHandler内部重写的handlerMessage方法帮我们将消息交给了onHandlerIntent来处理,而这个onHandlerIntent方法正是我们在派生IntentService子类的时候要重写的方法!所以最终消息的处理交给了我们自己处理,不得不佩服Android设计人员的聪明才智!