Android应用程序线程消息循环模型分析(2)

简介:

  2. 应用程序子线程消息循环模型

        在Java框架中,如果我们想在当前应用程序中创建一个子线程,一般就是通过自己实现一个类,这个类继承于Thread类,然后重载Thread类的run函数,把我们想要在这个子线程执行的任务都放在这个run函数里面实现。最后实例这个自定义的类,并且调用它的start函数,这样一个子线程就创建好了,并且会调用这个自定义类的run函数。但是当这个run函数执行完成后,子线程也就结束了,它没有消息循环的概念。

        前面说过,有时候我们需要在应用程序中创建一些常驻的子线程来不定期地执行一些计算型任务,这时候就可以考虑使用Android系统提供的HandlerThread类了,它具有创建具有消息循环功能的子线程的作用。

        HandlerThread类实现在frameworks/base/core/java/android/os/HandlerThread.java文件中,这里我们通过使用情景来有重点的分析它的实现。

        在前面一篇文章Android系统默认Home应用程序(Launcher)的启动过程源代码分析中,我们分析了Launcher的启动过程,其中在Step 15(LauncherModel.startLoader)和Step 16(LoaderTask.run)中,Launcher会通过创建一个HandlerThread类来实现在一个子线程加载系统中已经安装的应用程序的任务:

  1. public class LauncherModel extends BroadcastReceiver {  
  2.     ......  
  3.   
  4.     private LoaderTask mLoaderTask;  
  5.   
  6.     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");  
  7.     static {  
  8.         sWorkerThread.start();  
  9.     }  
  10.     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());  
  11.   
  12.     ......  
  13.   
  14.     public void startLoader(Context context, boolean isLaunching) {    
  15.         ......    
  16.   
  17.         synchronized (mLock) {    
  18.             ......    
  19.   
  20.             // Don't bother to start the thread if we know it's not going to do anything    
  21.             if (mCallbacks != null && mCallbacks.get() != null) {    
  22.                 ......  
  23.   
  24.                 mLoaderTask = new LoaderTask(context, isLaunching);    
  25.                 sWorker.post(mLoaderTask);    
  26.             }    
  27.         }    
  28.     }    
  29.   
  30.     ......  
  31.   
  32.     private class LoaderTask implements Runnable {    
  33.         ......    
  34.   
  35.         public void run() {    
  36.             ......    
  37.   
  38.             keep_running: {    
  39.                 ......    
  40.   
  41.                 // second step    
  42.                 if (loadWorkspaceFirst) {    
  43.                     ......    
  44.                     loadAndBindAllApps();    
  45.                 } else {    
  46.                     ......    
  47.                 }    
  48.   
  49.                 ......    
  50.             }    
  51.   
  52.             ......    
  53.         }    
  54.   
  55.         ......    
  56.     }   
  57.   
  58.     ......  
  59. }  

        在这个LauncherModel类中,首先创建了一个HandlerThread对象:

  1. private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");  

        接着调用它的start成员函数来启动一个子线程:

  1. static {  
  2.     sWorkerThread.start();  
  3. }  

        接着还通过这个HandlerThread对象的getLooper函数来获得这个子线程中的消息循环对象,并且使用这个消息循环创建对象来创建一个Handler:

  1. private static final Handler sWorker = new Handler(sWorkerThread.getLooper());  

        有了这个Handler对象sWorker之后,我们就可以往这个子线程中发送消息,然后在处理这个消息的时候执行加载系统中已经安装的应用程序的任务了,在startLoader函数中:

  1. mLoaderTask = new LoaderTask(context, isLaunching);    
  2. sWorker.post(mLoaderTask);    

        这里的mLoaderTask是一个LoaderTask对象,它实现了Runnable接口,因此,可以把这个LoaderTask对象作为参数传给sWorker.post函数。在sWorker.post函数里面,会把这个LoaderTask对象封装成一个消息,并且放入这个子线程的消息队列中去。当这个子线程的消息循环处理这个消息的时候,就会调用这个LoaderTask对象的run函数,因此,我们就可以在LoaderTask对象的run函数中通过调用loadAndBindAllApps来执行加载系统中已经安装的应用程序的任务了。

 

        了解了HanderThread类的使用方法之后,我们就可以重点地来分析它的实现了:

  1. public class HandlerThread extends Thread {  
  2.     ......  
  3.     private Looper mLooper;  
  4.   
  5.     public HandlerThread(String name) {  
  6.         super(name);  
  7.         ......  
  8.     }  
  9.   
  10.     ......  
  11.   
  12.     public void run() {  
  13.         ......  
  14.         Looper.prepare();  
  15.         synchronized (this) {  
  16.             mLooper = Looper.myLooper();  
  17.             ......  
  18.         }  
  19.         ......  
  20.         Looper.loop();  
  21.         ......  
  22.     }  
  23.   
  24.     public Looper getLooper() {  
  25.         ......  
  26.         return mLooper;  
  27.     }  
  28.   
  29.     ......  
  30. }  

        首先我们看到的是,HandlerThread类继承了Thread类,因此,通过它可以在应用程序中创建一个子线程,其次我们看到在它的run函数中,会进入一个消息循环中,因此,这个子线程可以常驻在应用程序中,直到它接收收到一个退出消息为止。

 

        在run函数中,首先是调用Looper类的静态成员函数prepare来准备一个消息循环对象:

  1. Looper.prepare();  

        然后通过Looper类的myLooper成员函数将这个子线程中的消息循环对象保存在HandlerThread类中的成员变量mLooper中:

  1. mLooper = Looper.myLooper();  

        这样,其它地方就可以方便地通过它的getLooper函数来获得这个消息循环对象了,有了这个消息循环对象后,就可以往这个子线程的消息队列中发送消息,通知这个子线程执行特定的任务了。

 

        最在这个run函数通过Looper类的loop函数进入消息循环中:

  1. Looper.loop();  

        这样,一个具有消息循环的应用程序子线程就准备就绪了。

 

        HandlerThread类的实现虽然非常简单,当然这得益于Java提供的Thread类和Android自己本身提供的Looper类,但是它的想法却非常周到,为应用程序开发人员提供了很大的方便。





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966878,如需转载请自行联系原作者
目录
相关文章
|
21天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
25天前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
2月前
|
并行计算 JavaScript 前端开发
单线程模型
【10月更文挑战第15天】
|
2月前
|
Java API Android开发
安卓应用程序开发的新手指南:从零开始构建你的第一个应用
【10月更文挑战第20天】在这个数字技术不断进步的时代,掌握移动应用开发技能无疑打开了一扇通往创新世界的大门。对于初学者来说,了解并学习如何从无到有构建一个安卓应用是至关重要的第一步。本文将为你提供一份详尽的入门指南,帮助你理解安卓开发的基础知识,并通过实际示例引导你完成第一个简单的应用项目。无论你是编程新手还是希望扩展你的技能集,这份指南都将是你宝贵的资源。
77 5
|
2月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
24 1
|
2月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
64 4
|
3月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
150 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
2月前
|
NoSQL Redis 数据库
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
本文解释了Redis为什么采用单线程模型,以及为什么Redis单线程模型的效率和速度依然可以非常高,主要原因包括Redis操作主要访问内存、核心操作简单、单线程避免了线程竞争开销,以及使用了IO多路复用机制epoll。
56 0
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
|
2月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
3月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
121 5