- 浏览: 47962 次
- 性别:
- 来自: 上海
最新评论
-
hanxie1121:
书读多了
思考一下!!!!my android -
huyong479072052:
不用说应届毕业生了,现在中国搞android的开发的有几个能达 ...
思考一下!!!!my android -
zhanhao:
顶!
思考一下!!!!my android -
cectsky:
你妈喊你回家吃饭
回调(callback)方法
Android中的Handler, Looper, MessageQueue和Thread
- 博客分类:
- android
前几天,和同事探讨了一下Android中的消息机制,探究了消息的发送和接收过程以及与线程之间的关系。虽然我们经常使用这些基础的东西,但对于其内部原理的了解,能使我们更加容易、合理地架构系统,并避免一些低级错误。
对于这部分的内容,将分成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:线程,负责调度整个消息循环,即消息循环的执行场所。
关系
[img]
Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。
2) 接下来,我们简单地看一下消息的循环过程:
生成
发送
在Handler.java的sendMessageAtTime(Message msg, long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。
抽取
在Looper.java的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next方法)Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。
处理
在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将不能接收处理消息。在这种情况下,通用的作法是:
在创建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方法
对于这部分的内容,将分成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:线程,负责调度整个消息循环,即消息循环的执行场所。
关系
[img]
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方法
发表评论
-
android 4.0 取内外置SD卡新特性
2013-06-06 12:44 1167private StorageManager mStorage ... -
android 2.3 取内外置SD卡
2013-06-06 12:42 1927在android2.3中 判断内置SD卡是否挂载: if( ... -
android 关闭数据连接方法
2013-05-04 21:18 1585开关数据连接方法: Method getITelepho ... -
Activity Task Task 栈
2011-12-03 15:30 11271、Activity和Task task就好像是能包含很多a ... -
判断Android 网络状态
2011-12-03 11:53 926当需要开启Activity之前需要检测网络状态的时候需要用到一 ... -
LauncherEx UI初探及Drag机制了解
2011-11-23 10:34 1见下载!! -
Android APK签名
2011-11-23 10:30 13481.签名的意义 为了保证每个应用程序开发商合法ID,防止部 ... -
Android 横竖屏设置
2011-11-17 09:03 1135最近遇到一个问题,关于Android 横竖屏的问题,我的lau ... -
Android 设计之流畅设计
2011-11-14 20:42 775即使你的应用程序是快速且响应灵敏的,但一些设计仍然会给用户造成 ... -
Android_WindowManager分析
2011-11-02 13:53 1Activity 建立一个主窗口 ... -
onInterceptTouchEvent和onTouchEvent调用时序
2011-10-22 17:01 824onInterceptTouchEvent()是ViewGro ... -
activity 启动方式
2011-10-15 11:15 846在android里,有4种activity ... -
Android功能总结:仿照Launcher的Workspace实现左右滑动切换
2011-10-09 17:36 2295对于Launcher的桌面滑动大家应该都比较熟悉了,最好的体验 ... -
ListView 动态加载
2011-09-29 20:46 1195ListView的动态加载,想必大家在网上都看过很多资料了。我 ... -
AppWidget加载流程(二)
2011-09-27 17:38 9441. 用户长按Launcher弹出添快捷组件的Dialog,选 ... -
AppWidget加载流程(一)
2011-09-27 17:34 12651. Android系统启动,SystemServer创建A ... -
Android(安卓) snippet
2011-09-21 10:33 01.获取屏幕的分辨率 在 activity 里利用如下编码,宽 ... -
Android 中Locale,auto-rotate状态的获取
2011-09-21 10:26 15501. 得到当前locale: Context.getReso ... -
深入理解Android消息处理系统——Looper、Handler、Thread
2011-09-19 10:56 1093熟悉Windows编程的朋友可能知道Windows程序是消息驱 ... -
理解Android系统的进程间通信原理(一)----RPC中的代理模式
2011-09-14 19:39 1073[size=medium]理解Android系统的进程间通信原 ...
相关推荐
【Android 线程间通信:Handler、Looper 和 MessageQueue 深度解析】 在 Android 应用开发中,为了保证界面的流畅性,我们通常需要将耗时操作放在非 UI 线程中执行,然后通过某种机制将结果传递回 UI 线程进行界面...
在Android系统中,线程(Thread)、Looper、Handler、Message以及MessageQueue和MessagePool是实现异步消息处理机制的关键组件,它们共同构建了一个高效的事件驱动模型。这些组件的关系紧密,协同工作,使得Android...
本文详细介绍了Android中消息处理机制的核心组件Looper、MessageQueue和Handler的工作原理及其实现细节。理解这些概念有助于开发者更好地设计和实现多线程应用程序,提高程序的性能和用户体验。通过合理利用这些组件...
Android 消息机制是 Android 程序设计中非常重要的一部分,其中 Handler、MessageQueue 和 Looper 是三个紧密相关的概念。Handler 是 Android 消息机制的上层接口,我们在开发过程中只需要和 Handler 交互即可。...
本文将深入探讨Android中的线程模型,重点讲解Handler、Message Queue和AsyncTask,并提供修改Button样式的示例以及如何将这些概念整合到一个易用的方案中。 1. **Android线程模型** Android系统的主线程,也称为...
4. **Looper**:充当MessageQueue和Handler之间的桥梁角色,负责循环取出MessageQueue中的消息,并交给对应的Handler处理。 #### 四、消息处理流程 1. **创建Handler**:每个需要处理消息的线程都需要一个Handler...
通过以上介绍可以看出,Android的Message机制是通过`Handler`、`Message`、`Looper`和`MessageQueue`四个关键组件协同工作来完成的。这种机制不仅使得应用程序内部通信变得更加高效有序,同时也为开发者提供了一种...
Handler是Android系统中用于线程间通信的关键组件,它的内部实现原理涉及到Thread、MessageQueue和Looper等核心类。首先,我们需要理解线程在操作系统中的基本概念,线程是程序执行的最小单位,每个线程都有自己的...
本文将深入探讨Message Queue的工作原理及其在Android中的应用。 1. **Message Queue的角色** - **UI线程与Message Queue**:在Android应用程序启动时,系统会为每个进程创建一个主线程,也称为UI线程,它自带一个...
在Android开发中,`Handler`是一个至关重要的组件,它用于在主线程中处理来自其他线程的消息,确保UI更新和事件处理的同步性。本文将详细介绍`Handler`的几种常见写法,以及如何使用`Handler.Callback`进行消息处理...
Handler是Android中的一个类,它用于在不同的线程之间发送和处理消息。通常,我们使用Handler配合Looper和Message来实现在主线程(UI线程)中执行后台任务的结果。Looper是消息队列的循环器,它不断检查消息队列并...
`Handler`, `Message`, `Looper` 和 `MessageQueue` 是 Android 应用开发中非常重要的组成部分,它们共同协作以实现多线程间的高效通信和任务调度。正确理解和运用这些机制对于提高应用性能和用户体验至关重要。
Looper 对象通过 MessageQueue 来存放消息和事件,每个线程只能有一个 Looper 对象,-corresponding to one MessageQueue。 Android 中的 Looper 对象可以通过以下三种方式创建: 1. 系统默认创建:在主线程中,...
Handler的主要职责是发送Message到MessageQueue和处理由Looper分发的消息。通过`handleMessage(Message)`方法,Handler可以执行特定的操作,比如更新UI。同时,`post(Runnable)`方法也可用于延迟执行Runnable对象。...
Handler、Looper和MessageQueue是Android系统中用于实现线程间通信的关键组件,它们共同构成了Android的消息处理机制。这里我们将深入探讨这些概念,并通过一个仿写Handler机制的例子来理解其工作原理。 首先,我们...
Handler提供一个Looper对象,因为...理解Handler、Looper和MessageQueue的工作原理以及它们之间的交互,对于编写高效、无阻塞的Android应用至关重要。在实际开发中,正确使用Handler可以避免ANR等问题,提升用户体验。
通过这个简单的计数器应用,我们可以理解`Handler`如何协同`Looper`和`MessageQueue`工作,以及如何在Android中实现定时任务,特别是涉及到UI更新的操作。这种机制在更复杂的异步编程和事件驱动设计中也扮演着关键...
首先,Handler是Android中的一个关键类,它允许开发者在不同的线程之间发送和处理消息。Handler的实例通常与特定的线程关联,当通过Handler发送一个Message时,这个Message就会被添加到与该Handler关联的Message...
总结来说,Thread和Handler是Android中实现多线程和UI更新的核心工具。Thread用于执行后台任务,而Handler则提供了一种安全地在主线程中执行UI更新的方式,确保应用的响应性和稳定性。理解并熟练运用这两个概念,...
为了管理这些任务,Android引入了Looper、Handler和MessageQueue。MessageQueue是一个先进先出(FIFO)的队列,用于存储待处理的消息或任务。Handler则充当消息的生产者和消费者,它将消息放入MessageQueue,并在...