【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )(一)

简介: 【Android】Handler 机制 ( Handler | Message | Looper | MessageQueue )(一)

I . Handler 机制简介


Handler 机制是 Android 中最重要的 异步通信 机制 ;




1 . Handler 机制作用 : 将需要执行的任务分配给其它线程 ;



① 子线程更新 UI : 在子线程中更新 UI , 就是在子线程中将刷新 UI 的任务分配给了主线程 ; ( 子线程刷新 UI 会崩溃 )


② 主线程网络操作 : 在主线程中 , 将网络通信等耗时的操作分配给子线程 ( 该子线程需要转成 Looper 线程 ) , 避免 UI 卡顿 ; ( 主线程访问网络会崩溃 )




2 . Handler 机制中涉及到的组件 :



① Handler ( 消息处理者 ) : 定义具体的代码操作逻辑 , 处理收到消息 ( Message ) 后的具体操作 ;


② Message ( 消息 ) : 定义具体消息 , 其中可以封装不同的变量 , 为 Handler 指定操作的类型 , 或执行操作所需的数据 ;


③ Looper ( 消息遍历者 ) : 消息的遍历者 , 遍历 MessageQueue 中的消息 , 分发给 Handler 处理 ;


④ MessageQueue ( 消息队列 ) : 封装在 Looper 中 , 每个 Looper 中封装了一个 MessageQueue , 是 Looper 消息遍历的重要组件 , 用户不直接调用该组件 ;




3 . Handler 机制中的 封闭性 与 线程交互 :



① 线程内部相对封闭的运行系统 : 整个 Looper 线程内部是一个封闭运行的系统 , Looper 一直不停的再遍历 MessageQueue , 将 消息 或 操作 取出 , 交给 Handler 执行 ;


② 线程交互 : Handler 还有另外一个职责就是负责与外部线程的交互 , 在外部线程中调用 Handler 将消息回传给本 Looper 线程 , 放入 MessageQueue 队列中 ;




4 . Message ( 消息 ) 的运行路径 ( 重点 ) : 在外部线程中 , 调用 Looper 线程的 Handler 成员 , 将 Message ( 消息 ) 发送给 Looper 线程中的 MessageQueue ( 消息队列 ) , 然后 Looper 轮询该 消息队列时 , 又将该消息交给 Handler 进行处理 ;


Message -> Handler ( 发送 ) -> MessageQueue ( 存储 ) -> Looper ( 轮询 ) -> Handler ( 执行 )






II . Handler 机制 Handler Message Looper MessageQueue 四组件对应关系


Handler , Message , Looper , MessageQueue 四组件对应关系 :



Handler 机制中的上述四者的对应关系 : 一个线程中只能有一个 Looper 及 Looper 中封装的 MessageQueue , 每个 Looper 可以为多个 Handler 调度消息 , Message 消息可以有无数个 ;



Looper 是 线程本地存储的对象 ( ThreadLocal ) , 一个线程只能存在一个 , MessageQueue ( 消息队列 ) 定义在 Looper 内部 , 每个 Looper 中只定义了一个 MessageQueue ( 消息队列 ) , 因此每个线程也只能有一个 MessageQueue ;



线程 与 Looper ( 消息遍历者 ) 是一对一关系 , Looper ( 消息遍历者 ) 与 MessageQueue ( 消息队列 ) 是一对一的关系 , Looper ( 消息遍历者 ) 与 Handler ( 消息处理者 ) 是一对多的关系 , Message ( 消息 ) 可以有很多 ;






III . Handler ( 消息处理者 )


1 . Handler 创建 : 这里注意 只能在 Looper 线程中创建 Handler , 普通线程不能创建 Handler ;



① 主线程 : 主线程中可以直接创建 Handler , 因为在点击应用图标后就会 启动主线程 ActivityThread , 此时就已经将 Looper 实例化好了 , 因此我们在 Activity 中 , 可以任意创建多个 Handler , 并直接使用 ;


public final class ActivityThread {
  ...
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
  //创建 ActivityThread 线程, 并运行
        ActivityThread thread = new ActivityThread();
        //attach 方法 进行 thread 的最初初始化操作 
        thread.attach(false);
        ...
        Looper.loop();
        ...
    }//main
    ...
}//ActivityThread



② 子线程 : 子线程如果要创建 Handler , 需要先 调用 Looper.prepare() 方法 , 将线程转为 Looper 线程 , 因为 创建 Handler 时 , 会关联线程的 Looper 对象 , 普通的子线程是没有 Looper 对象的 , 调用 Looper.prepare() 方法即可为该线程创建 Looper 对象 , 该线程也就转为了 Looper 线程 ;


public class handler {
  ...
  //获取 Looper 对象后 , 可以从 Looper 对象中获取 MessageQueue
  //关联后 , Handler 发送消息时 , 才能将消息精准的发送给
  final MessageQueue mQueue;
  //Handler 需要与线程的唯一 Looper 对象关联
    final Looper mLooper;  
    ...
    public Handler() {
      ...
  mLooper = Looper.myLooper()
  if (mLooper == null) {
    throw new RuntimeException(
    "Can't create handler inside thread that has not called Looper.prepare()");
  }
  ...
  mQueue = mLooper.mQueue;
  ...
  }
  ...
}


2 . Handler 对象个数 : 每个 Looper 线程可以创建多个 Handler , 只要该 Handler 与 Looper 和 MessageQueue 关联 , 就可以将 消息 ( Message ) 发送给 Looper 线程中的 MessageQueue 中 ; Looper 轮询该 消息队列 ( MessageQueue ) , 将消息再次分发给对应的 Handler 进行处理 ;






IV . Looper ( 消息遍历者 )


1 . Looper 线程 : 如果要将 Handler , Looper 机制引入到线程中 , 使某线程具有接收 Message ( 消息 ) , 执行某项操作的功能 , 需要将该线程转为 Looper 线程 ;



2 . Looper 线程可执行的操作 : 一个线程如果被转为 Looper 线程 , 那这个线程运行后只能接收 Message 消息 , 执行对应的操作 , 运行后永远卡在 loop 循环遍历的 while (true) 循环中 , 使用 quit() 方法才能退出 ;



3 . Loop.prepare() 方法 : 该方法是将 普通子线程 转为 Looper 线程最终要的方法 , 该方法的主要作用是 创建 Looper , 然后将 Looper 对象放入 ThreadLocal 对象中存储 ; 线程只有创建了 Looper 对象才能创建 Handler , 将该 Looper 对象及其中封装的 MessageQueue 与 Handler 进行关联 , Handler 才可以进行消息的调度 ; 如果线程中没有 Looper 对象 , 创建 Handler 会报运行时异常 ;


public final class Looper {
  ...
  // sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
  ...
  private static void prepare(boolean quitAllowed) {
      if (sThreadLocal.get() != null) {
          throw new RuntimeException("Only one Looper may be created per thread");
      }
      sThreadLocal.set(new Looper(quitAllowed));
  }
  ...
}



4 . Loop.loop() 方法 : 一旦调用了该方法 , 就意味着该 Looper 线程进入到了轮询 MessageQueue 的阶段 , 这是一个无限死循环 , 调用了该方法后 , Handler 发送消息 , 线程才能处理对应的业务逻辑 ;



调用 quit() 方法 , 可以终止该遍历 MessageQueue 操作 ;


下面代码删除了大部分代码 , 只留下 循环遍历 和 调度 Message 信息给 Handler 进行处理 ;


public static void loop() {
    final Looper me = myLooper();
    ...
    final MessageQueue queue = me.mQueue;
    ...
    for (;;) {
        Message msg = queue.next(); // 阻塞
        if (msg == null) {
            // 循环遍历退出
            return;
        }
        ...
        try {
          //调度 Message 信息给 Handler 进行处理 
            msg.target.dispatchMessage(msg);
            ...
        } 
        ...
    }
}




目录
相关文章
|
5天前
|
算法 Linux 调度
深入探索安卓系统的多任务处理机制
【10月更文挑战第21天】 本文旨在为读者提供一个关于Android系统多任务处理机制的全面解析。我们将从Android操作系统的核心架构出发,探讨其如何管理多个应用程序的同时运行,包括进程调度、内存管理和电量优化等方面。通过深入分析,本文揭示了Android在处理多任务时所面临的挑战以及它如何通过创新的解决方案来提高用户体验和设备性能。
12 1
|
11天前
|
存储 安全 Android开发
探索Android与iOS的隐私保护机制
在数字化时代,移动设备已成为我们生活的一部分,而隐私安全是用户最为关注的问题之一。本文将深入探讨Android和iOS两大主流操作系统在隐私保护方面的策略和实现方式,分析它们各自的优势和不足,以及如何更好地保护用户的隐私。
|
29天前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
5天前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
11天前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义视图:打造个性化UI组件
【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
|
12天前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异和挑战
【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
|
14天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
12天前
|
存储 API 开发工具
探索安卓开发:从基础到进阶
【10月更文挑战第37天】在这篇文章中,我们将一起探索安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和建议。我们将从安卓开发的基础开始,逐步深入到更复杂的主题,如自定义组件、性能优化等。最后,我们将通过一个代码示例来展示如何实现一个简单的安卓应用。让我们一起开始吧!
|
13天前
|
存储 XML JSON
探索安卓开发:从新手到专家的旅程
【10月更文挑战第36天】在这篇文章中,我们将一起踏上一段激动人心的旅程,从零基础开始,逐步深入安卓开发的奥秘。无论你是编程新手,还是希望扩展技能的老手,这里都有适合你的知识宝藏等待发掘。通过实际的代码示例和深入浅出的解释,我们将解锁安卓开发的关键技能,让你能够构建自己的应用程序,甚至贡献于开源社区。准备好了吗?让我们开始吧!
24 2
|
14天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!