首页>
技术资讯>
详情

应用程序线程消息循环模型分析

2016-05-13 来源:佚名 阅读量: 0
关键词: 手机开发

  我们知道,Android应用程序是通过消息来驱动的,即在应用程序的主线程(UI线程)中有一个消息循环,负责处理消息队列中的消息。我们也知道,Android应用程序是支持多线程的,即可以创建子线程来执行一些计算型的任务,那么,这些子线程能不能像应用程序的主线程一样具有消息循环呢?这些子线程又能不能往应用程序的主线程中发送消息呢?本文将分析Android应用程序线程消息处理模型,为读者解答这两个问题

        在开发Android应用程序中,有时候我们需要在应用程序中创建一些常驻的子线程来不定期地执行一些不需要与应用程序界面交互的计算型的任务。如果这些子线程具有消息循环,那么它们就能够常驻在应用程序中不定期的执行一些计算型任务了:当我们需要用这些子线程来执行任务时,就往这个子线程的消息队列中发送一个消息,然后就可以在子线程的消息循环中执行我们的计算型任务了。我们在前面一篇文章Android系统默认Home应用程序(Launcher)的启动过程源代码分析中,介绍Launcher的启动过程时,在Step 15(LauncherModel.startLoader)中,Launcher就是通过往一个子线程的消息队列中发送一个消息(sWorker.post(mLoaderTask)),然后子线程就会在它的消息循环中处理这个消息的时候执行从PackageManagerService中获取系统中已安装应用程序的信息列表的任务,即调用Step 16中的LoaderTask.run函数。

        在开发Android应用程序中,有时候我们又需要在应用程序中创建一些子线程来执行一些需要与应用程序界面进交互的计算型任务。典型的应用场景是当我们要从网上下载文件时,为了不使主线程被阻塞,我们通常创建一个子线程来负责下载任务,同时,在下载的过程,将下载进度以百分比的形式在应用程序的界面上显示出来,这样就既不会阻塞主线程的运行,又能获得良好的用户体验。但是,我们知道,Android应用程序的子线程是不可以操作主线程的UI的,那么,这个负责下载任务的子线程应该如何在应用程序界面上显示下载的进度呢?如果我们能够在子线程中往主线程的消息队列中发送消息,那么问题就迎刃而解了,因为发往主线程消息队列的消息最终是由主线程来处理的,在处理这个消息的时候,我们就可以在应用程序界面上显示下载进度了。

        上面提到的这两种情况,Android系统都为我们提供了完善的解决方案,前者可以通过使用HandlerThread类来实现,而后者可以使用AsyncTask类来实现,本文就详细这两个类是如何实现的。不过,为了更好地理解HandlerThread类和AsyncTask类的实现,我们先来看看应用程序的主线程的消息循环模型是如何实现的。

        1. 应用程序主线程消息循环模型

        在前面一篇文章"Android应用程序进程启动过程的源代码分析"一文中,我们已经分析应用程序进程(主线程)的启动过程了,这里主要是针对它的消息循环模型作一个总结。当运行在Android应用程序框架层中的ActivityManagerService决定要为当前启动的应用程序创建一个主线程的时候,它会在ActivityManagerService中的startProcessLocked成员函数调用Process类的静态成员函数start为当前应用程序创建一个主线程:

    public final class ActivityManagerService extends ActivityManagerNative      
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

......

private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {

......

try {
int uid = app.info.uid;
int[] gids = null;
try {
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
} catch (PackageManager.NameNotFoundException e) {
......
}

......

int debugFlags = 0;

......

int pid = Process.start("android.app.ActivityThread",
mSimpleProcessManagement ? app.processName : null, uid, uid,
gids, debugFlags, null);

......

} catch (RuntimeException e) {

......

}
}

......

}