Android应用程序线程的消息循环模型
- Android应用程序线程的三种消息循环模型:
- 应用程序主线程消息循环模型。
- 与界面无关的应用程序子线程消息循环模型。
- 与界面相关的应用程序子线程消息循环模型。
我们可以使用ActivityThread、HandlerThread和AysncTask这三个类来分别实现上述三种消息循环模型。
#1.应用程序主线程消息循环模型
#2.与界面无关的应用程序子线程消息循环模型
#3.与界面相关的应用程序子线程消息循环模型
#1. 应用程序主线程消息循环模型
Activity管理服务ActivityManagerService在启动一个应用程序组件时,如果发现这个应用程序组件需要在一个新的应用程序进程中运行,那么就会调用Process类的静态成员函数start来请求Zygote进程来创建一个新的应用程序进程。
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
Process类的静态成员函数start的第一个参数用来指定新创建的应用程序进程在创建完成之后需要加载的类,并且是以这个类的静态成员函数main作为新创建的应用程序进程的入口函数的。Android应用程序的主线程是以ActivityThread类的静态成员函数main作为入口函数:
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
Looper类的prepareMainLooper()在当前应用程序线程中创建一个消息循环,Looper类的loop()使得当前应用程序主线程进入到前面创建的消息循环当中。Looper.prepareMainLooper()当中创建的Looper对象除了保存在一个线程局部变量当中之外,还会单独保存在Looper类的静态成员变量sMainLooper当中。这样可以通过静态成员函数getMainLooper()对主线程的Looper进行访问,这样就可以在应用程序子线程中获取到主线程的Looper对象,通过它可以往主线程的消息队列中发送UI消息,从而解决子线程不能直接操作UI的问题。
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
#2. 与界面无关的应用程序子线程消息循环模型
- Android应用程序子线程是使用Thread类来描述,一般是先实现一个Thread子类,然后使用这个Thread子类来创建一个Android应用程序子线程。
- 为了创建一个具有消息循环模型的应用程序子线程,可以通过Android应用程序框架层提供的HandlerThread类来实现。
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
使用HandlerThread类创建一个Android应用程序子线程。
- #Step1:首先创建一个HandlerThread子类实例,调用start()来开启一个子线程:
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
- #Step2:定义一个实现了Runnable接口的类,例如ThreadHanlder类,用来描述一个子线程中所执行的任务:
public class ThreadTask implements Runnable {
@Override
public void run() {
//start
//execute the task.
//exit
}
}
- #Step3:创建一个ThreadTask实例,如下所示:
ThreadTask threadTask = new ThreadTask();
- #Step4:将ThreadTask类实例封装成消息发送到前面所创建的一个子线程的消息对立中了,如下所示:
Handler handler = new Handler(handlerThread.getLooper());
handler.post(threadTask);
当这个消息被处理时,前面所创建的的一个子线程就会调用ThreadTask类的成员函数run,以便执行自定义任务。
NT: 当我们不往这个子线程的消息队列中发送消息,那么它就会因为它的消息队列为空而进入睡眠等待状态。
#3. 与界面相应的应用程序子线程消息循环模型
- Android系统在应用程序框架层中提供了一个异步任务类AsyncTask,用来将一个涉及界面操作的任务放在子线程中执行。用来执行异步任务的子线程虽然没有自己的消息循环,但是它会利用主线程的消息循环来执行与界面相关的操作。
异步任务类AsyncTask的实现:
- #Step1: AysncTask成员变量的定义:
public abstract class AsyncTask {
private static final String LOG_TAG = "AsyncTask";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE_SECONDS = 30;
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 BlockingQueue sPoolWorkQueue =
new LinkedBlockingQueue(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR;
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static InternalHandler sHandler;
private final WorkerRunnable mWorker;
private final FutureTask mFuture;
}
异步任务类AsyncTask是一个泛类,它有三个类型参数Params、Progress和Result,分别用来描述一个异步任务的输入数据、过程数据和结果数据类型。
异步任务类AysncTask的静态成员变量sPoolWorkQueue指向一个==LinkedBlockingQueue==的工作任务队列,保存在这个队列中的每一个任务都是使用一个实现了Runnable接口的对象来描述的。
一个类型为LinkedBlockingQueue的工作任务队列有以下两个特性:
- 一个线程如果试图从一个空的LinkedBlockingQueue队列中取出一个工作任务来执行,那么它会被阻塞,直到这个队列有新的工作任务添加进来为止。
- 一个线程如果试图往一个满的LinkedBlockingQueue队列中添加一个新的工作任务,那么它同样会被阻塞,直到这个队列腾出来新的空闲位置为止。
异步任务类AsyncTask的静态成员变量sThreadFactory指向线程工厂==ThreadFactory==;threadPoolExecutor指向类型为==ThreadPoolExecutor==的线程池,保存在线程池中的线程通过线程工厂来创建,并且用来执行保存在静态成员变量sPoolWorkQueue中的工作任务。
ThreadPoolExecutor线程池的工作原理如下:
#1.ThreadPoolExecutor类构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
corePoolSize和maximumPoolSize用来描述线程池的核心线程数量和最大线程数量。当一个
ThreadPoolExecutor线程池的线程数量大于核心线程数量时,保存在它里面的空闲线程就会被设置一个存活时间,时间长度由参数keepAliveTime决定,时间单位由unit决定。workQueue和threadFactory分别描述一个线程池的工作任务队列和线程创建工厂。
#2. ThreadPoolExecutor.execute()
当我们需要在线程池中执行一个工作任务时,需要将待执行的工作任务封装成为一个实现了Runnable接口的对象,接着调用ThreadPoolExecutor的成员函数execute将这个对象添加到这个ThreadPoolExecutor线程池中去执行。execute具体工作方式如下:
- 如果线程池中的线程数量小于核心线程数量,那么它就会创建一个新的线程来执行新添加进来的工作任务。
- 如果线程池中的线程数量等于或者大于核心线程数量,但是小于最大线程数量。这时候:
- 如果工作任务队列处于未满的状态,那么就会将新添加进来的工作任务保存在工作任务队列中等待执行。
- 如果工作任务队列处于已满的状态,那么它就会创建一个新的线程来执行新添加进来的工作任务。
- 如果线程池中的线程数量等于或者大于最大线程数量,这时候:
- 如果工作任务队列处于未满的状态,那么它就会将新添加的工作任务保存在任务队列中等待执行。
- 如果工作任务队列处于已满的状态,那么它就会拒绝指向新添加进来的工作任务。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
InternalHandler类与应用程序主线程消息队列相关,其作用为更新主线程UI。
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@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;
}
}
}