对于不定期的后台任务来说,有两种处理方式。
(1)每当条件满足,就创建一个子线程来执行一个不定期的后台任务;当任务执行完毕后,新创建的子线程随之退出。
(2)创建一个具有消息循环的子线程,每当条件满足时,就将一个不定期的后台任务封装成一个消息发送到这个子线程的消息队列中去执行;当条件不满足时,子线程因为消息队列为空而进入睡眠等待状态。Android采用第2种。
Android应用程序线程的三种消息循环模型。
(1)应用程序主线程消息循环模型
(2)与界面无关的应用程序子线程消息循环模型
(3)与界面相关的应用程序子线程消息循环模型
1 应用程序主线程消息循环模型ActivityThread
AMS在启动一个应用程序组件时,如果发现这个应用程序组件需要在一个新的应用程序进程中进行,就会调用Process类的静态成员函数start来请求Zygote进程创建一个新的应用程序进程。
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) {
...
try {
...
int pid = Process.start("android.app.ActivityThread", mSimpleProcessManagement ? app.processName : null,
uid, uid, gids, debugFlags, null);
} catch (RuntimeException e) {
...
}
}
}
每一个新创建的应用程序进程(主线程)都是以ActivityThread类的静态成员函数main来作为入口函数的。
frameworks/base/core/java/android/app/ActivityThread.java
public final class ActivityThread {
...
public static final void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
}
prepareMainLooper函数在当前应用程序主线程中创建一个消息循环,loop函数使得当前应用程序主线程进入到前面创建的消息循环中。
prepareMainLooper首先创建一个Looper对象,描述一个应用程序主线程的消息循环;然后在Looper对象上创建一个MessageQueue对象,描述一个应用程序主线程的消息队列。prepareMainLooper只能在应用程序主线程中调用,且只能被调用一次,否则系统抛出运行时异常。
为什么Looper类要单独为应用程序主线程提供一个创建Looper对象的函数呢?
Looper对象除了会保存在一个线程局部变量中之外,还会单独保存在Looper类的静态成员变量mMainLooper中。这样,应用程序子线程就可以通过这个mMainLooper对象向主线程的消息队列发送与UI相关的消息了。
2 与界面无关的应用程序子线程消息循环模型HandlerThread
通过一个例子来说明如何使用一个Thread子类来创建一个Android应用程序子线程:
public class SubThread extends Thread {
public SubThread(String name) {
super(name);
}
public void run() {
...
}
}
SubThread subThread = new SubThread("Sub Thread");
subThread.start();
创建SubThread类实例,调用start函数来启动一个子线程:
SubThread subThread = new SubThread("Sub Thread");
subThread.start();
为了创建一个具有消息循环的应用程序子线程,可以通过framework层提供的HandlerThread类来实现:
frameworks/base/core/java/android/os/HandlerThread.java
public class HandlerThread extends Thread {
...
private Looper mLooper;
public HandlerThread(String name) {
super(name);
...
}
public void run() {
...
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
}
Looper.loop();
...
}
public Looper getLooper() {
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
}
Looper类的prepare函数用作子线程创建一个消息循环,loop函数使得当前线程进入到前面所创建的消息循环中。
来说明下如何使用HandlerThread类创建一个Android应用子线程:
(1)创建HandlerThread类实例,调用start函数来启动一个子线程:
HandlerThread handlerThread = new HandlerThread("Handler Thread");
handlerThread.start();
(2)定义一个实现了Runnable接口的类,用来描述任务:
public class ThreadTask implements Runnable {
public ThreadTask() {
}
public void run() {
...
}
}
(3)创建一个ThreadTask类实例:
ThreadTask threadTask = new ThreadTask();
(4)将ThreadTask类实例封装成一个消息发送到HandlerThread子线程的消息队列中:
Handler handler = new Handler(handlerThread.getLooper());
handler.post(threadTask);
当这个消息被处理时,HandlerThread子线程会调用ThreadTask的run函数。
(5)需要结束子线程时:
handlerThread.quit();
frameworks/base/core/java/android/os/Looper.java
public class Looper {
....
final MessageQueue mQueue;
public void quit() {
Message msg = Message.obtain();
// a quit message
mQueue.enqueueMessage(msg, 0);
}
};
如果我们向一个线程的消息队列发送的target为null的Message对象,那么这个线程会退出消息循环。
3 与界面相关的应用程序子线程消息循环模型AsyncThread
异步任务类AsyncTask,子线程虽然没有自己的消息循环,但是它可以利用主线程的消息循环来执行与UI相关的操作。
CounterService,当调用startCounter函数时,它会在一个子线程中执行异步任务。这个异步任务每隔1秒就会将它内部的一个计数值增加1,且将计数值更新到UI上。
package/xxx/CounterService.java
public class CounterService extends Service implements ICounterService {
...
private ICounterCallback counterCallback = null;
public void startCounter(int initVal, ICounterCallback callback) {
counterCallback = callback;
AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {
@Override //子线程
protected Integer doInBackground(Integer... vals) {
Integer initCounter = vals[0];
stop = false;
while(!stop) {
publishProgress(initCounter);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
initCounter++;
}
return initCounter;
}
@Override //主线程
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int val = values[0];
counterCallback.count(val);
}
@Override //主线程
protected void onPostExecute(Integer val) {
counterCallback.count(val);
}
};
task.execute(initVal);
}
}
callback是一个计数器回调接口,调用它的count函数可以将计数值更新到UI上。
异步任务task是在doInBackground中执行的,运行在子线程中。每隔1s会将计数值加一,调用publishProgress将计数值分发给onProgressUpdate来处理,onProgressUpdate会调用回调将计数值显示在UI上。doInBackground的返回值会分发给onPostExecute来处理,onPostExecute会调用回调将计数值显示在UI上。
onProgressUpdate和onPostExecute执行了与UI有关的操作,推断出它们是在应用程序主线程中运行的。
可以看出,一个异步任务虽然是在子线程中执行的,但是它可以执行与UI有关的操作,来分析下:
先看下异步任务类AsyncTask类的定义:
frameworks/base/core/java/android/os/AsyncTask.java
public abstract class AsyncTask<Params, Progress, Result> {
...
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static final int MESSAGE_POST_CANCEL = 0x3;
private static final InternalHandler sHandler = new InternalHandler();
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
}
类型参数Params、Progress和Result,分别描述异步任务的输入数据、过程数据和结果数据。
sWorkQueue表示工作任务队列,队列为空时阻塞,队列满时也阻塞。
sThreadFactory表示一个类型为ThreadFactory的线程创建工厂,创建的线程用来执行sWorkQueue队列里的任务。
sExecutor表示一个类型为ThreadPoolExecutor的线程池,保存在线程池的线程是sThreadFactory创建的。
ThreadPoolExcutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory);
corePoolSize:核心线程数量
maximumPoolSize:最大线程数量
当线程池中的线程数量大于核心线程数量时,里面的空闲线程会设置一个存活时间,由keepAliveTime来描述,时间单位由unit来描述。
workQueue:工作任务队列
threadFactory:线程创建工厂
由于sWorkQueue、sThreadFactory和sExecutor都是静态成员变量,因此,在一个应用程序进程中,所有使用异步任务类AsyncTask来描述的异步任务都是在同一个线程池中执行的。
sHandler指向一个Handler对象,静态变量是在程序第一次使用时创建的,假设应用程序第一次使用异步任务类AsyncTask时是运行在主线程的,那么sHandler所指向的Handler就是在应用程序的主线程中创建的,这意味着它可以用来向应用程序主线程的消息队列发送消息。
mWorker和mFuture用来描述一个工作任务。
来看下InternalHandler:
frameworks/base/core/java/android/os/AsyncTask.java
public abstract class AsyncTask<Params, Progress, Result> {
...
private static class InternalHandler extends Handler {
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
case MESSAGE_POST_CANCEL:
result.mTask.onCanceled();
break;
}
}
}
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
}
MESSAGE_POST_RESULT,MESSAGE_POST_PROGRESS和MESSAGE_POST_CANCEL都是由异步任务的子线程发送到主线程的消息队列的。
mTask表示一个宿主异步任务。mParams数组用来保存一个异步任务的输入数据。
下面,来分析一个异步任务的创建过程:
frameworks/base/core/java/android/os/AsyncTask.java
public abstract class AsyncTask<Params, Progress, Result> {
...
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
...
return doInBackground(mParams);
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
Message message;
Result result = null;
try {
result = get();
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException();
} catch (CancellationException e) {
message = sHandler.obtainMessage(MESSAGE_POST_CANCEL, new AsyncTaskResult<Result>(AsyncTask.this, null));
message.sendToTarget();
return;
} catch (Throwable t) {
throw new RuntimeException();
}
message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(AsyncTask.this, result));
message.sendToTarget();
}
};
}
}
一个异步任务在创建完成之后,就会在内部获得一个mWorker和mFuture,它们共同描述了一个即将执行的工作任务。
当工作任务执行完成后,done被调用。done函数会封装一个类型为MESSAGE_POST_RESULT的消息,通过sHandler对象将这个消息发送到应用程序主线程的消息队列中。mFuture.get()用来描述一个工作任务的执行结果数据,返回值对应于AsyncTask类的函数doInBackground的返回值。
一个异步任务在执行过程中是可以被取消的。这种情况下,在获取结果数据时,会得到一个类型为CancellationException的异常,done函数会封装一个类型为MESSAGE_POST_CANCEL的消息,通过sHandler对象将这个消息发送到应用程序主线程的消息队列中。
下面继续分析这个工作任务的执行过程:
public abstract class AsyncTask<Params, Progress, Result> {
...
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
...
mWorker.mParams = params;
sExecutor.execute(mFuture);
return this;
}
protected abstract Result doInBackground(Params... params);
}
mFuture描述的工作任务,加入到线程池中去执行。执行过程中,会调用内部的一个Callable对象的call函数,这个Callable对象就是mWorker对象,进而调用doInBackground函数。doInBackground是一个抽象方法,AsyncTask子类通过重写这个方法就可以执行一个自定义的异步任务。
1 MESSAGE_POST_PROGRESS
一个异步任务在执行的过程中,如果需要执行与界面相关的操作,那么它就需要调用异步任务类AsyncTask的函数publishProgress,以便可以向应用程序主线程的消息队列发送一个消息。
public abstract class AsyncTask<Params, Progress, Result> {
...
protected final void publishProgress(Progress... values) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
protected void onProgressUpdate(Progress... values) {
}
}
sHandler发送的消息最终是由成员函数handleMessage来处理的。MESSAGE_POST_PROGRESS消息会由onProgressUpdate函数来处理。AsyncTask子类通过重写这个方法可以在一个异步任务的执行过程中执行一系列与界面相关(主线程)的操作。
2 MESSAGE_POST_RESULT
从handleMessage可以看出,类型为MESSAGE_POST_RESULT的消息最终是在AsyncTask的finish函数中处理的。
public abstract class AsyncTask<Params, Progress, Result> {
...
private void finish(Result result) {
if (isCancelled()) result = null;
onPostExecute(result);
...
}
protected void onPostExecute(Result result) {
}
}
AsyncTask子类通过重写这个方法可以在一个异步任务的执行完成时执行与界面相关(主线程)的操作。
3 MESSAGE_POST_CANCEL
从handleMessage可以看出,类型为MESSAGE_POST_CANCEL的消息最终是在AsyncTask的onCancelled函数中处理的。
public abstract class AsyncTask<Params, Progress, Result> {
...
protected void onCancelled() {
}
}
AsyncTask子类通过重写这个方法可以在一个异步任务被取消时执行与界面相关(主线程)的操作。