Android消息处理机制_第1页
Android消息处理机制_第2页
Android消息处理机制_第3页
Android消息处理机制_第4页
Android消息处理机制_第5页
已阅读5页,还剩42页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Google 参考了 Windows 的消息处理机制 在 Android 系统中实现了一套类似的消息处 理机制 学习 Android 的消息处理机制 有几个概念 类 必须了解 1 Message 消息 理解为线程间通讯的数据单元 例如后台线程在处理数据完毕后需要更新 UI 则可 发送一条包含更新信息的 Message 给 UI 线程 2 Message Queue 消息队列 用来存放通过 Handler 发布的消息 按照先进先出执行 3 Handler Handler 是 Message 的主要处理者 负责将 Message 添加到消息队列以及对消息队列 中的 Message 进行处理 4 Looper 循环器 扮演 Message Queue 和 Handler 之间桥梁的角色 循环取出 Message Queue 里面的 Message 并交付给相应的 Handler 进行处理 5 线程线程 UI thread 通常就是 main thread 而 Android 启动程序时会替它建立一个 Message Queue 每一个线程里可含有一个 Looper 对象以及一个 MessageQueue 数据结构 在你的应用 程序里 可以定义 Handler 的子类别来接收 Looper 所送出的消息 运行机理 运行机理 每个线程都可以并仅可以拥有一个 Looper 实例 消息队列 MessageQueue 在 Looper 的构造函数中被创建并且作为成员变量被保存 也就是说 MessageQueue 相对 于线程也是唯一的 Android 应用在启动的时候会默认会为主线程创建一个 Looper 实例 并借助相关的 Handler 和 Looper 里面的 MessageQueue 完成对 Activities Services Broadcase Receivers 等的管理 而在子线程中 Looper 需要 通过显式调用 Looper Prepare 方法进行创建 Prepare 方法通过 ThreadLocal 来保 证 Looper 在线程内的唯一性 如果 Looper 在线程内已经被创建并且尝试再度创建 Only one Looper may be created per thread 异常将被抛出 Handler 在创建的时候可以指定 Looper 这样通过 Handler 的 sendMessage 方法发送出去的消息就会添加到指定 Looper 里面的 MessageQueue 里面去 在不指定 Looper 的情况下 Handler 绑定的是创建它的线程的 Looper 如果这个线程的 Looper 不存在 程序将抛出 Can t create handler inside thread that has not called Looper prepare 整个消息处理的大概流程是 1 包装 Message 对象 指定 Handler 回调函数和 携带数据等 2 通过 Handler 的 sendMessage 等类似方法将 Message 发送出去 3 在 Handler 的处理方法里面将 Message 添加到 Handler 绑定的 Looper 的 MessageQueue 4 Looper 的 loop 方法通过循环不断从 MessageQueue 里面提取 Message 进行处理 并移除处理完毕的 Message 5 通过调用 Message 绑定的 Handler 对象的 dispatchMessage 方法完成对消息的处理 在 dispatchMessage 方法里 如何处理 Message 则由用户指定 三个判断 优 先级从高到低 1 Message 里面的 Callback 一个实现了 Runnable 接口的对象 其中 run 函数做处理工作 2 Handler 里面 mCallback 指向的一个实现了 Callback 接口的 对象 由其 handleMessage 进行处理 3 处理消息 Handler 对象对应的类继承并实现 了其中 handleMessage 函数 通过这个实现的 handleMessage 函数处理消息 Android 的消息机制的消息机制 一一 android 有一种叫消息队列的说法 这里我们可以这样理解 假如一个隧道就是一个消息 队列 那么里面的每一部汽车就是一个一个消息 这里我们先忽略掉超车等种种因素 只 那么先进隧道的车将会先出 这个机制跟我们 android 的消息机制是一样的 一 角色描述 1 Looper 相当于隧道 一个线程可以产生一个 Looper 对象 由它来管理此线程里 的 Message Queue 车队 消息隧道 2 Handler 你可以构造 Handler 对象来与 Looper 沟通 以便 push 新消息到 Message Queue 里 或者接收 Looper 从 Message Queue 取出 所送来的消息 3 Message Queue 消息队列 用来存放线程放入的消息 4 线程 UI thread 通常就是 main thread 而 Android 启动程序时会替它建立一 个 Message Queue 每一个线程里可含有一个 Looper 对象以及一个 MessageQueue 数据结构 在你的 应用程序里 可以定义 Handler 的子类别来接收 Looper 所送出的消息 在你的 Android 程序里 新诞生一个线程 或执行 Thread 时 并不会自动建立其 Message Loop Android 里并没有 Global 的 Message Queue 数据结构 例如 不同 APK 里的对 象不能透过 Massage Queue 来交换讯息 Message 例如 线程 A 的 Handler 对象可以传递消息给别的线程 让别的线程 B 或 C 等能送 消息来给线程 A 存于 A 的 Message Queue 里 线程 A 的 Message Queue 里的讯息 只有线程 A 所属的对象可以处理 使用 Looper myLooper 可以取得当前线程的 Looper 对象 使用 mHandler new EevntHandler Looper myLooper 可用来构造当前线 程的 Handler 对象 其中 EevntHandler 是自已实现的 Handler 的子类别 使用 mHandler new EevntHandler Looper getMainLooper 可诞生用来处 理 main 线程的 Handler 对象 其中 EevntHandler 是自已实现的 Handler 的子类别 这样描述可能太抽像 下面举几个实际的例子来说明 二 举例 1 同线程内不同组件间的消息传递 Looper 类用来管理特定线程内对象之间的消息交换 Message Exchange 你的应 用程序可以产生许多个线程 而一个线程可以有许多个组件 这些组件之间常常需要互相 交换讯息 如果有这种需要 您可以替线程构造一个 Looper 对象 来担任讯息交换的管 理工作 Looper 对象会建立一个 MessageQueue 数据结构来存放各对象传来的消息 包 括 UI 事件或 System 事件等 如下图 每一个线程里可含有一个 Looper 对象以及一个 MessageQueue 数据结构 在你的 应用程序里 可以定义 Handler 的子类别来接收 Looper 所送出的消息 同线程不同组件之间的消息传递 publicclass Activity1extends Activityimplements OnClickListener Buttonbutton null TextViewtext null Override protectedvoid onCreate Bundle savedInstanceState super onCreate savedInstanceState setContentView R layout activity1 button Button findViewById R id btn button setOnClickListener this text TextView findViewById R id content publicvoid onClick View v switch v getId case R id btn Looper looper Looper myLooper 取得当前线程里的 looper MyHandler mHandler new MyHandler looper 构造一个 handler 使之可 与 looper 通信 buton 等组件可以由 mHandler 将消息传给 looper 后 再放入 messageQueue 中 同时 mHandler 也可以接受来自 looper 消息 mHandler removeMessages 0 String msgStr 主线程不同组件通信 消息来自 button Message m mHandler obtainMessage 1 1 1 msgStr 构造要传递 的消息 mHandler sendMessage m 发送消息 系统会自动调用 handleMessage 方 法来处理消息 break privateclass MyHandlerextends Handler public MyHandler Looper looper super looper Override publicvoid handleMessage Message msg 处理消息 text setText msg obj toString 说明 此程序启动时 当前线程 即主线程 main thread 已诞生了一个 Looper 对象 并 且有了一个 MessageQueue 数据结构 looper Looper myLooper 调用 Looper 类别的静态 myLooper 函数 以取得目前线程里的 Looper 对象 mHandler new MyHandler looper 构造一个 MyHandler 对象来与 Looper 沟通 Activity 等对象可以藉由 MyHandler 对 象来将消息传给 Looper 然后放入 MessageQueue 里 MyHandler 对象也扮演 Listener 的角色 可接收 Looper 对象所送来的消息 Message m mHandler obtainMessage 1 1 1 obj 先构造一个 Message 对象 并将数据存入对象里 mHandler sendMessage m 就透过 mHandler 对象而将消息 m 传给 Looper 然后放入 MessageQueue 里 此时 Looper 对象看到 MessageQueue 里有消息 m 就将它广播出去 mHandler 对 象接到此讯息时 会呼叫其 handleMessage 函数来处理 于是输出 This my message 于画面上 Android 消息处理机制消息处理机制 二二 角色综述 回顾 1 UI thread 通常就是 main thread 而 Android 启动程序时会替它建立一个 MessageQueue 2 当然需要一个 Looper 对象 来管理该 MessageQueue 3 我们可以构造 Handler 对象来 push 新消息到 Message Queue 里 或者接收 Looper 从 Message Queue 取出 所送来的消息 4 线程 A 的 Handler 对象可以传递给别的线程 让别的线程 B 或 C 等能送讯息来给 线程 A 存于 A 的 Message Queue 里 5 线程 A 的 Message Queue 里的消息 只有线程 A 所属的对象可以处理 子线程传递消息给主线程 publicclass Activity2extends Activityimplements OnClickListener Buttonbutton null TextViewtext null MyHandlermHandler null Threadthread Override protectedvoid onCreate Bundle savedInstanceState super onCreate savedInstanceState setContentView R layout activity1 button Button findViewById R id btn button setOnClickListener this text TextView findViewById R id content publicvoid onClick View v switch v getId case R id btn thread new MyThread thread start break privateclass MyHandlerextends Handler public MyHandler Looper looper super looper Override publicvoid handleMessage Message msg 处理消息 text setText msg obj toString privateclass MyThreadextends Thread Override publicvoid run Looper curLooper Looper myLooper Looper mainLooper Looper getMainLooper String msg if curLooper null mHandler new MyHandler mainLooper msg curLooper is null else mHandler new MyHandler curLooper msg This is curLooper mHandler removeMessages 0 Message m mHandler obtainMessage 1 1 1 msg mHandler sendMessage m 说明 Android 会自动替主线程建立 Message Queue 在这个子线程里并没有建立 Message Queue 所以 myLooper 值为 null 而 mainLooper 则指向主线程里 的 Looper 于是 执行到 mHandler new MyHandler mainLooper 此 mHandler 属于主线程 mHandler sendMessage m 就将 m 消息存入到主线程的 Message Queue 里 mainLooper 看到 Message Queue 里有讯息 就会作出处理 于是由主线程执行到 mHandler 的 handleMessage 来处理 消息 用用 Android 线程间通信的线程间通信的 Message 机制机制 在 Android 下面也有多线程的概念 在 C C 中 子线程可以是一个函数 一般都是一 个带有循环的函数 来处理某些数据 优先线程只是一个复杂的运算过程 所以可能不需 要 while 循环 运算完成 函数结束 线程就销毁 对于那些需要控制的线程 一般我们 都是和互斥锁相互关联 从而来控制线程的进度 一般我们创建子线程 一种线程是很常 见的 那就是带有消息循环的线程 消息循环是一个很有用的线程方式 曾经自己用 C 在 Linux 下面实现一个消息循环的机制 往消息队列里添加数据 然后异步的等待消息的返回 当消息队列为空的时候就会挂起线 程 等待新的消息的加入 这是一个很通用的机制 在 Android 这里的线程分为有消息循环的线程和没有消息循环的线程 有消息循环的线 程一般都会有一个 Looper 这个事 android 的新概念 我们的主线程 UI 线程 就是一 个消息循环的线程 针对这种消息循环的机制 我们引入一个新的机制 Handle 我们有 消息循环 就要往消息循环里面发送相应的消息 自定义消息一般都会有自己对应的处理 消息的发送和清除 消息的的处理 把这些都封装在 Handle 里面 注意 Handle 只是针 对那些有 Looper 的线程 不管是 UI 线程还是子线程 只要你有 Looper 我就可以往你 的消息队列里面添加东西 并做相应的处理 但是这里还有一点 就是只要是关于 UI 相关的东西 就不能放在子线程中 因为子线程 是不能操作 UI 的 只能进行数据 系统等其他非 UI 的操作 那么什么情况下面我们的子线程才能看做是一个有 Looper 的线程呢 我们如何得到它 Looper 的句柄呢 Looper myLooper 获得当前的 Looper Looper getMainLooper 获得 UI 线程的 Lopper 我们看看 Handle 的初始化函数 如果没有参数 那么他就默认使用的是当前的 Looper 如果有 Looper 参数 就是用对应的线程的 Looper 如果一个线程中调用 Looper prepare 那么系统就会自动的为该线程建立一个消息队 列 然后调用 Looper loop 之后就进入了消息循环 这个之后就可以发消息 取消息 和处理消息 这个如何发送消息和如何处理消息可以再其他的线程中通过 Handle 来做 但前提是我们的 Hanle 知道这个子线程的 Looper 但是你如果不是在子线程运行 Looper myLooper 一般是得不到子线程的 looper 的 public void run synchronized mLock Looper prepare do something Looper loop 所以很多人都是这样做的 我直接在子线程中新建 handle 然后在子线程中发送消息 这样的话就失去了我们多线程的意义了 class myThread extends Thread private EHandler mHandler public void run Looper myLooper mainLooper myLooper Looper myLooper mainLooper Looper getMainLooper String obj if myLooper null mHandler new EHandler mainLooper obj current thread has no looper else mHandler new EHandler myLooper obj This is from current thread mHandler removeMessages 0 Message m mHandler obtainMessage 1 1 1 obj mHandler sendMessage m 可以让其他的线程来控制我们的 handle 可以把 private EHandler mHandler 放在外 面 这样我们的发消息和处理消息都可以在外面来定义 这样增加程序代码的美观 结构 更加清晰 对如任何的 Handle 里面必须要重载一个函数 public void handleMessage Message msg 这个函数就是我们的消息处理 如何处理 这里完全取决于你 然后通过 obtainMessage 和 sendMessage 等来生成和发送消息 removeMessages 0 来清 除消息队列 Google 真是太智慧了 这种框架的产生 我们写代码更加轻松了 有的时候 我们的子线程想去改变 UI 了 这个时候千万不要再子线程中去修改 获得 UI 线程的 Looper 然后发送消息即可 我们看看 Goole Music App 的源代码 在 MediaPlaybackActivity java 中 我们可以看一下再 OnCreate 中的有这样的两句 mAlbumArtWorker new Worker album art worker mAlbumArtHandler new AlbumArtHandler mAlbumArtWorker getLooper 很明显这两句 是构建了一个子线程 并且这个子线程还是 Looper 的子线程 这里很牛 逼的使用了 mAlbumArtWorker getLooper 这个函数 因为我们知道 我们能够得到 子线程的 Looper 的途径只有一个 就是在子线程中调用 Looper myLooper 并且这 个函数还要在我们 perpare 之后调用才能得到正确的 Looper 但是他这里用了一个这样 的什么东东 getLooper 不知道它是如何实现的 这里有一个大概的思路 我们在子线程的的 prepare 之后调用 myLooper 这个方法 然后保存在一个成员变量中 这个 getLooper 就返回这个东西 但是这里会碰到多线程的 一个很突出的问题 同步 我们在父线程中调用 mAlbumArtWorker getLooper 但 是想要这个返回正确的 looper 就必须要求我们的子线程运行了 prepare 但是这个东西 实在子线程运行的 我们如何保证呢 我们看 Google 是如何实现的 private class Worker implements Runnable private final Object mLock new Object private Looper mLooper Creates a worker thread with the given name The thread then runs a email 7B link link email android os Looper param name A name for the new thread Worker String name Thread t new Thread null this name t setPriority Thread MIN PRIORITY t start synchronized mLock while mLooper null try mLock wait catch InterruptedException ex public Looper getLooper return mLooper public void run synchronized mLock Looper prepare mLooper Looper myLooper mLock notifyAll Looper loop public void quit mLooper quit 我们知道 一个线程类的构造函数是在主线程中完成的 所以在我们的 Worker 的构造函 数中我们创佳一个线程 然后让这个线程运行 这一这个线程的创建是指定一个 Runnabl 这里就是我们的 Worker 本身 在主线程调用 t start 这后 我们子线程 已经创建 并且开始执行 work 的 run 方法 然后下面的代码很艺术 synchronized mLock while mLooper null try mLock wait catch InterruptedException ex 我们开始等待我们的子线程给 mLooper 赋值 如果不赋值我们就继续等 然后我们的子 线程在运行 run 方法之后 在给 mLooper 赋值之后 通知 worker 够着函数中的 wait 然后我们的构造函数才能完成 所以我们说 mAlbumArtWorker new Worker album art worker 这句本身就是阻塞的 它创建了一个子线程 开启了子线程 并且等待子线程给 mLooper 赋值 赋值完成之后 这个函数才返回 这样才能保证我们的子线程的 Looper 的获取绝对是正确的 这个构思很有创意 值得借鉴 Android 中中 Handler 的使用方法的使用方法 在子线程中更新界面在子线程中更新界面 本文主要介绍 Android 的 Handler 的使用方法 Handler 可以发送 Messsage 和 Runnable 对象到与其相关联的线程的消息队列 每个 Handler 对象与创建它的线程相关 联 并且每个 Handler 对象只能与一个线程相关联 1 Handler 一般有两种用途 1 执行计划任务 你可以再预定的实现执行某些任务 可以模拟定时器 2 线程间通信 在 Android 的应用启动时 会创建一个主线程 主线 程会创建一个消息队列来处理各种消息 当你创建子线程时 你可以再你的子线程中拿到 父线程中创建的 Handler 对象 就可以通过该对象向父线程的消息队列发送消息了 由于 Android 要求在 UI 线程中更新界面 因此 可以通过该方法在其它线程中更新界面 通过 Runnable 在子线程中更新界面的例子 1 在 onCreate 中创建 Handler public class HandlerTestApp extends Activity Handler mHandler TextView mText Called when the activity is first created Override public void onCreate Bundle savedInstanceState super onCreate savedInstanceState setContentView R layout main mHandler new Handler 创建 Handler mText TextView findViewById R id text0 一个 TextView 构建 Runnable 对象 在 runnable 中更新界面 此处 我们修改了 TextView 的文字 此处需要说明的是 Runnable 对象可以再主线程中创建 也可以再子线程中创建 我们此处是在子线程中创建的 Runnable mRunnable0 new Runnable Override public void run mText setText This is Update from ohter thread Mouse DOWN 创建子线程 在线程的 run 函数中 我们向主线程的消息队列发送了一个 runnable 来更新界面 private void updateUIByRunnable new Thread Message msg mHandler obtainMessage public void run mText setText This is Update from ohter thread Mouse DOWN 这句将抛出异常 mHandler post mRunnable0 start 用 Message 在子线程中来更新界面 1 用 Message 更新界面与 Runnable 更新界面类似 只是需要修改几个地方 实现自己的 Handler 对消息进行处理 private class MyHandler extends Handler Override public void handleMessage Message msg super handleMessage msg switch msg what case UPDATE 在收到消息时 对界面进行更新 mText setText This update by message break 在新的线程中发送消息 private void updateByMessage 匿名对象 new Thread public void run mText setText This is Update from ohter thread Mouse DOWN UPDATE 是一个自己定义的整数 代表了消息 ID Message msg mHandler obtainMessage UPDATE mHandler sendMessage msg start 华丽的分割线 android 的消息处理有三个核心类 Looper Handler 和 Message 其实还有一个 Message Queue 消息队列 但是 MQ 被封装到 Looper 里面了 我们不会直接与 MQ 打交道 因此我没将其作为核心类 下面一一介绍 线程的魔法师线程的魔法师 Looper Looper 的字面意思是 循环者 它被设计用来使一个普通线程变成 Looper 线程线程 所谓 Looper 线程就是循环工作的线程 在程序开发中 尤其是 GUI 开发中 我们经常会需 要一个线程不断循环 一旦有新任务则执行 执行完继续等待下一个任务 这就是 Looper 线程 使用 Looper 类创建 Looper 线程很简单 public class LooperThread extends Thread Override public void run 将当前线程初始化为 Looper 线程 Looper prepare 其他处理 如实例化 handler 开始循环处理消息队列 Looper loop 通过上面两行核心代码 你的线程就升级为 Looper 线程了 是不是很神奇 让我们 放慢镜头 看看这两行代码各自做了什么 1 Looper prepare 通过上图可以看到 现在你的线程中有一个 Looper 对象 它的内部维护了一个消息队列 MQ 注意 一个一个 Thread 只能有一个只能有一个 Looper 对象对象 为什么呢 咱们来看源码 public class Looper 每个线程中的 Looper 对象其实是一个 ThreadLocal 即线程本地存储 TLS 对象 private static final ThreadLocal sThreadLocal new ThreadLocal Looper 内的消息队列 final MessageQueue mQueue 当前线程 Thread mThread 其他属性 每个 Looper 对象中有它的消息队列 和它所属的线程 private Looper mQueue new MessageQueue mRun true mThread Thread currentThread 我们调用该方法会在调用线程的 TLS 中创建 Looper 对象 public static final void prepare if sThreadLocal get null 试图在有 Looper 的线程中再次创建 Looper 将抛出异常 throw new RuntimeException Only one Looper may be created per thread sThreadLocal set new Looper 其他方法 通过源码 prepare 背后的工作方式一目了然 其核心就是将 looper 对象定义为 ThreadLocal 如果你还不清楚什么是 ThreadLocal 请参考 理解 ThreadLocal 2 Looper loop 调用 loop 方法后 Looper 线程就开始真正工作了 它不断从自己的 MQ 中取出队头的消 息 也叫任务 执行 其源码分析如下 public static final void loop Looper me myLooper 得到当前线程 Looper MessageQueue queue me mQueue 得到当前 looper 的 MQ 这两行没看懂 不过不影响理解 Binder clearCallingIdentity final long ident Binder clearCallingIdentity 开始循环 while true Message msg queue next 取出 message if msg null if msg target null message 没有 target 为结束信号 退出循环 return 日志 if me mLogging null me mLogging println Dispatching to msg target msg callback msg what 非常重要 将真正的处理工作交给 message 的 target 即后面要讲的 handler msg target dispatchMessage msg 还是日志 if me mLogging null me mLogging println Finished to msg target msg callback 下面没看懂 同样不影响理解 final long newIdent Binder clearCallingIdentity if ident newIdent Log wtf Looper Thread identity changed from 0 x Long toHexString ident to 0 x Long toHexString newIdent while dispatching to msg target getClass getName msg callback what msg what 回收 message 资源 msg recycle 除了 prepare 和 loop 方法 Looper 类还提供了一些有用的方法 比如 Looper myLooper 得到当前线程 looper 对象 public static final Looper myLooper 在任意线程调用 Looper myLooper 返回的都是那个线程的 looper return Looper sThreadLocal get getThread 得到 looper 对象所属线程 public Thread getThread return mThread quit 方法结束 looper 循环 public void quit 创建一个空的 message 它的 target 为 NULL 表示结束循环消息 Message msg Message obtain 发出消息 mQueue enqueueMessage msg 0 到此为止 你应该对 Looper 有了基本的了解 总结几点 1 每个线程有且最多只能有一个 Looper 对象 它是一个 ThreadLocal 2 Looper 内部有一个消息队列 loop 方法调用后线程开始不断从队列中取出消息执行 3 Looper 使一个线程变成 Looper 线程 那么 我们如何往 MQ 上添加消息呢 下面有请 Handler 掌声 异步处理大师异步处理大师 Handler 什么是 handler handler 扮演了往 MQ 上添加消息和处理消息的角色 只处理由自己发 出的消息 即通知通知 MQ 它要执行一个任务它要执行一个任务 sendMessage 并在 并在 loop 到自己的时候到自己的时候 执行该任务执行该任务 handleMessage 整个过程是异步的 整个过程是异步的 handler 创建时会关联一个 looper 默认的构造方法将关联当前线程的 looper 不过这也是可以 set 的 默认的构造 方法 public class handler final MessageQueue mQueue 关联的 MQ final Looper mLooper 关联的 looper final Callback mCallback 其他属性 public Handler 没看懂 直接略过 if FIND POTENTIAL LEAKS final Class klass getClass if klass isAnonymousClass klass isMemberClass klass isLocalClass 默认将关联当前线程的 looper mLooper Looper myLooper looper 不能为空 即该默认的构造方法只能在 looper 线程中使用 if mLooper null throw new RuntimeException Can t create handler inside thread that has not called Looper prepare 重要 直接把关联 looper 的 MQ 作为自己的 MQ 因此它的消息将发送到关联 looper 的 MQ 上 mQueue mLooper mQueue mCallback null 其他方法 下面我们就可以为之前的 LooperThread 类加入 Handler public class LooperThread extends Thread private Handler handler1 private Handler handler2 Override public void run 将当前线程初始化为 Looper 线程 Looper prepare 实例化两个 handler handler1 new Handler handler2 new Handler 开始循环处理消息队列 Looper loop 加入 handler 后的效果如下图 可以看到 一个线程可以有多个一个线程可以有多个 Handler 但是只能有一个 但是只能有一个 Looper Handler 发送消息发送消息 有了 handler 之后 我们就可以使用 post Runnable postAtTime Runnable long postDelayed Runnable long sendEmptyMessage int sendMessage Message sendMessageAtTime M essage long 和 sendMessageDelayed Message long 这些方法向 MQ 上发送消息 了 光看这些 API 你可能会觉得 handler 能发两种消息 一种是 Runnable 对象 一种 是 message 对象 这是直观的理解 但其实 post 发出的 Runnable 对象最后都被封装 成 message 对象了 见源码 public final boolean post Runnable r 注意 getPostMessage r 将 runnable 封装成 message return sendMessageDelayed getPostMessage r 0 private final Message getPostMessage Runnable r Message m Message obtain 得到空的 message m callback r 将 runnable 设为 message 的 callback return m public boolean sendMessageAtTime Message msg long uptimeMillis boolean sent false MessageQueue queue mQueue if queue null msg target this message 的 target 必须设为该 handler sent queue enqueueMessage msg uptimeMillis else RuntimeException e new RuntimeException this sendMessageAtTime called with no mQueue Log w Looper e getMessage e return sent 其他方法就不罗列了 总之通过 handler 发出的 message 有如下特点 1 message target 为该 handler 对象 这确保了 looper 执行到该 message 时能找到 处理它的 handler 即 loop 方法中的关键代码 msg target dispatchMessage msg 2 post 发出的 message 其 callback 为 Runnable 对象 Handler 处理消息处理消息 说完了消息的发送 再来看下 handler 如何处理消息 消息的处理是通过核心方法 dispatchMessage Message msg 与钩子方法 handleMessage Message msg 完成 的 见源码 处理消息 该方法由 looper 调用 public void dispatchMessage Message msg if msg callback null 如果 message 设置了 callback 即 runnable 消息 处理 callback handleCallback msg else 如果 handler 本身设置了 callback 则执行 callback if mCallback null 这种方法允许让 activity 等来实现 Handler Callback 接口 避免了自 己编写 handler 重写 handleMessage 方法 见 http alex yang xiansoftware if mCallback handleMessage msg return 如果 message 没有 callback 则调用 handler 的钩子方法 handleMessage handleMessage msg 处理 runnable 消息 private final void handleCallback Message message message callback run 直接调用 run 方法 由子类实现的钩子方法 public void handleMessage Message msg 可以看到 除了 handleMessage Message msg 和 Runnable 对象的 run 方法由开发 者实现外 实现具体逻辑 handler 的内部工作机制对开发者是透明的 这正是 handler API 设计的精妙之处 Handler 的用处的用处 我在小标题中将 handler 描述为 异步处理大师 这归功于 Handler 拥有下面两个重要 的特点 1 handler 可以在任意线程发送消息任意线程发送消息 这些消息会被添加到关联的 MQ 上 2 handler 是在它关联的关联的 looper 线程中处理消息线程中处理消息的 这就解决了 android 最经典的不能在其他非主线程中更新 UI 的问题 android 的主线程的主线程 也是一个也是一个 looper 线程线程 looper

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论