android中的Handler 对于这部分的内容,将分成4 小节来描述: 1)职责与关系 2)消息循环 3)线程与更新 4)几点小结 ---------------------------------------------------------------------------------------------- 1) 接下来,我们开始这部分的内容,首先了解一下各自的职责及相互之间的关系。 职责 Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue 统一列队,终由 Handler 处理。 Handler:处理者,负责Message 的发送及处理。使用Handler 时,需要实现handleMessage(Message msg) 方法来对特定的Message 进行处理,例如更新UI 等。 MessageQueue:消息队列,用来存放Handler 发送过来的消息,并按照FIFO 规则执行。当然,存放Message 并非实际意义的保存,而是将Message 以链表的方式串联起来的,等待Looper 的抽取。 Looper:消息泵,不断地从MessageQueue 中抽取Message 执行。因此,一个MessageQueue 需要一Looper。 Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
关系 class Class Model Looper MessageQueue Handler Handler,Looper 和MessageQueue 就是简单的三角关系。Looper 和MessageQueue 一 一对应,创建一个Looper 的同时,会创建一个MessageQueue。而Handler 与它们的关 系,只是简单的聚集关系,即Handler 里会引用当前线程里的特定Looper 和MessageQueue。 这样说来,多个Handler 都可以共享同一Looper 和MessageQueue 了。当然,这些 Handler 也就运行在同一个线程里。
2) 接下来,我们简单地看一下消息的循环过程: 生成 Message msg = mHandler.obtainMessage(); msg.what = what; msg.sendToTarget();
发送 MessageQueue queue = mQueue; if (queue != null) { msg.target = this; sent = queue.enqueueMessage(msg, uptimeMillis); } 在Handler.java 的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看 到,它找到它所引用的MessageQueue,然后将Message 的target 设定成自己(目的是 为了在处理消息环节,Message 能找到正确的Handler),再将这个Message 纳入到消 息队列中。
抽取 Looper me = myLooper(); MessageQueue queue = me.mQueue; while (true) { Message msg = queue.next(); // might block if (msg != null) { if (msg.target == null) { // No target is a magic identifier for the quit message. return; } msg.target.dispatchMessage(msg); msg.recycle(); } } 在Looper.java 的loop()函数里,我们看到,这里有一个死循环,不断地从 MessageQueue 中获取下一个(next 方法)Message,然后通过Message 中携带的 target 信息,交由正确的Handler 处理(dispatchMessage 方法)。
处理 if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } 在Handler.java 的dispatchMessage(Message msg)方法里,其中的一个分支就是调用 handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler 时需要实现handleMessage(Message msg)的原因。 至于dispatchMessage 方法中的另外一个分支,我将会在后面的内容中说明。 至此,我们看到,一个Message 经由Handler 的发送,MessageQueue 的入队,Looper 的抽取,又再一次地回到Handler 的怀抱。而绕的这一圈,也正好帮助我们将同步操作 变成了异步操作。
3) 剩下的部分,我们将讨论一下Handler 所处的线程及更新UI 的方式。 在主线程(UI 线程)里,如果创建Handler 时不传入Looper 对象,那么将直接使用主 线程(UI 线程)的Looper 对象(系统已经帮我们创建了);在其它线程里,如果创建 Handler 时不传入Looper 对象,那么,这个Handler 将不能接收处理消息。在这种情况 下,通用的作法是: class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } } 在创建Handler 之前,为该线程准备好一个Looper(Looper.prepare),然后让这个 Looper 跑起来(Looper.loop),抽取Message,这样,Handler 才能正常工作。 因此,Handler 处理消息总是在创建Handler 的线程里运行。而我们的消息处理中,不 乏更新UI 的操作,不正确的线程直接更新UI 将引发异常。因此,需要时刻关心 Handler 在哪个线程里创建的。
如何更新UI 才能不出异常呢?SDK 告诉我们,有以下4 种方式可以从其它线程访问UI 线程: · Activity.runOnUiThread(Runnable) · View.post(Runnable) · View.postDelayed(Runnable, long) · Handler 其中,重点说一下的是View.post(Runnable)方法。在post(Runnable action)方法里, View 获得当前线程(即UI 线程)的Handler,然后将action 对象post 到Handler 里。 在Handler 里,它将传递过来的action 对象包装成一个Message(Message 的callback 为action),然后将其投入UI 线程的消息循环中。在Handler 再次处理该Message 时, 有一条分支(未解释的那条)就是为它所设,直接调用runnable 的run 方法。而此时, 已经路由到UI 线程里,因此,我们可以毫无顾虑的来更新UI。
4) 几点小结 · Handler 的处理过程运行在创建Handler 的线程里 · 一个Looper 对应一个MessageQueue · 一个线程对应一个Looper · 一个Looper 可以对应多个Handler · 不确定当前线程时,更新UI 时尽量调用post 方法

更多相关文章

  1. Android(安卓)SurfaceView
  2. Android抓包方法
  3. okhttp源码学习分析一
  4. Android开发经验总结
  5. Android倒计时实现
  6. android dialog 背景透明的样式
  7. Android(安卓)框架:快速开发中Util常用工具类总结
  8. Android之动态改变控件大小
  9. radiolog不全的问题

随机推荐

  1. Android(安卓)模拟器中AVD路径的修改
  2. Android中处理崩溃异常
  3. Android(安卓)- Android(安卓)Studio 的
  4. android 中Fragment的生命周期1
  5. Android开发环境配置教程
  6. Android代码混淆常见配置
  7. ionic3修改android安装显示的名称
  8. android handler和AsyncTask用法
  9. Android-sharedUserId数据权限
  10. android设置背景平铺