Android的消息处理机制——Looper,Handler和Message浅析
题外话:
说来有些惭愧,对于这三者的初步认识居然是在背面试题的时候。那个时候自己接触Android的时间还不长,学习的书籍也就是比较适合入门的《疯狂Android讲义》,当然在学到Handler这一部分的时候,书中也是有提到一些简单示例,后来在工作中需要用到这个MessageQueue的时候才开始真正琢磨了一下这三者的联系。如果想要对这三者好好理解一番,个人还是比较推荐《深入理解Android卷Ⅰ》。以下对这三者之间的恩怨纠葛的介绍和分析也是参考这本书的相关章节,算是一篇读书笔记吧。
概述:
Android的消息传递机制是另一种形式的“事件处理”,这种机制主要是为了解决Android应用中的多线程问题——Android平台只允许UI线程修改Activity中的UI组件,这就使得新启动的线程无法去动态修改界面组件中的属性值。但是我们的程序界面不可能是一个静态的呈现,所以这就必须用到本博客中提到的三个大类了。
简单示例:
代码展示:
public class LooperThreadActivity extends Activity {private final int MSG_HELLO = 0;private Handler mHandler;private CustomThread mThread = null;private static final String TAG = LooperThreadActivity.class.getSimpleName();@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mThread = new CustomThread();mThread.start();Button sendButton = (Button) findViewById(R.id.send_button);final EditText contentEditText = (EditText) findViewById(R.id.content_edittext);sendButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String msgText = contentEditText.getText().toString();sendMessage(msgText);}});}private void sendMessage(String content) {Toast.makeText(this, "send msg: " + content, 0).show();// TODO 1.向MessageQueue中添加消息// 通过Message.obtain()来从消息池中获得空消息对象,以节省资源Log.i(TAG, "------------> send msg 1.");Message msg = mHandler.obtainMessage(MSG_HELLO, content);msg.sendToTarget();Log.i(TAG, "------------> send msg 2.");Message msg2 = mHandler.obtainMessage(MSG_HELLO, content + "2");msg2.sendToTarget();}class CustomThread extends Thread {@Overridepublic void run() {Looper.prepare();Log.i(TAG, "------------> loop.pre.");mHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case MSG_HELLO:Log.i(TAG, "------------> receive msg.");Toast.makeText(LooperThreadActivity.this, "receive msg: " + (String) msg.obj, 0).show();}}};Looper.loop();}}
}
运行效果展示:
Log结果展示:
示例结果分析:
大家可以看到我做了连续两次的添加消息数据,在结果中也有很好的体现,不过Looper.prepare();和Handler之间的内容却只执行了一次。这是因为我们自定义的线程CustomThread只被start了一次,且start过后一直存在,没有被销毁,所以Looper一直存在,MessageQueue一直存在,从而保证了一个Thread只能有一个Looper对象。对于这一点下面会用源码进行进一步的说明。
机制浅析:
就应用程序而言,Android系统中Java的应用程序和其他系统上相同,都是靠消息驱动来工作的。Android系统中的消息驱动离不开Looper、Handler和Message这三者,虽说不上哪个更重要一些,不过相对突出的的确是Looper。下面就对这些类逐一地介绍。
Looper类分析:
1.Looper.prepare();
跟踪prepare()进入Android的源码,我们可以发现以下源代码:
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));}
sThreadLocal定义:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
从以上源码中我们可以看到,在调用prepare的线程中,设置了一个Looper对象,这个Looper对象就保存在这个调用线程的TLV中。而Looper对象内部封装了一个消息队列。也就是说prepare通过ThreadLocal机制,把Looper和调用线程关联在了一起。
2.Looper.loop();
跟踪loop()进入Android的源码(此处删除了一些暂时不太关联的代码):
public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}msg.target.dispatchMessage(msg);msg.recycle();}
}
通过上面的分析,Looper有以下几个作用:
- 封装了一个消息队列.
- prepare函数把当前的Looper和调用prepare的线程(即最终的处理线程)绑定在了一起.
- 处理线程调用loop,处理来自该消息队列中的消息.
当事件源向这个Looper发送消息的时候,其实就是把消息加到这个Looper的消息列队里了。那么,该消息就将由和Looper绑定的处理来处理。
Handler类分析:
学习Handler之初先来认识一下Handler中所包含的部分成员:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
在Handler类中,它的构造函数会把Handler中的消息队列变量最终都会指向Looper的消息队列。由于是被指向,那么Handler中的消息队列其实就是某个Looper的消息队列。
Looper和Handler的同步关系说明及HandlerThread的介绍:
Looper和Handler之间其实是存在着同步关系的。这里对它们之间的同步关系不做过多介绍,如果想了解可以参看《深入理解Android卷Ⅰ》第128页。笔者在此只提出一个提醒点:由于HandlerThread完美地解决了Looper和Handler同步过程中可能出现的空指针异常问题,所以在以后的开发过程中,我们还是多用HandlerThread吧。当然如果不想使用它,那就请使用锁机制来健壮你的代码吧,不过这就可能会落下重复造轮子的口舌了。
参考资料:
1.《疯狂Android讲义》
2.《深入理解Android卷Ⅰ》
3.网络资源:http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html
4.网络资源:http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html
5.网络资源:http://blog.csdn.net/mylzc/article/details/6771331
尾声:
虽然已经“稀里糊涂”到了结尾,不过对Looper、Handler和Message的认识的确进了一大步。希望看完本文的你也有所收获。
Android的消息处理机制——Looper,Handler和Message浅析相关推荐
- Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析
1.Handler的由来 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程. Android的UI操作并不是线程安全的 ...
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android ...
- 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message
原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...
- android的消息处理机制(图文+源码分析)—Looper/Handler/Message[转]
from:http://www.jb51.net/article/33514.htm 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.andro ...
- Android多线程----异步消息处理机制之Handler
虽然是国庆佳节,但也不能停止学习的脚步,我选择在教研室为祖国母亲默默地庆生. 关于Android的多线程知识,请参考本人之前的一篇博客:Android 多线程----AsyncTask异步任务详解 在 ...
- Android之多线程----异步消息处理机制之Handler详解
一.handler的引入: 我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟 ...
- 通过源码分析Android 的消息处理机制
2019独角兽企业重金招聘Python工程师标准>>> #通过源码分析Android 的消息处理机制 我们知道,Android应用是通过消息来驱动的,每一个进程被fork之后,都会在 ...
- Android异步消息处理机制 全解析
Android异步消息处理机制主要是指Handler的运行机制以及Hanlder所附带的MessageQueue和Looper的工作过程. 本文将通过分析源码(api-28)的形式,全面解析Handl ...
- Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper
异步消息处理机制解析 Android中的异步消息处理主要有四个部分组成,Message.Handler.MessageQueue和Looper. 1.Message Message是在线程之间传递的消 ...
最新文章
- 职场PUA到底有多可怕?
- ORACLE 中为什么要把列名都转换成大写字母?
- C# 操纵 Excel(tlbimp.exe)
- wopi php,Office Online Server WOPI 接口
- python创建虚拟环境时出现拒绝访问_无法创建虚拟环境
- Intellij mac快捷键
- 小牛uqi几个版本区别_川崎ZX25R便宜版本长这样?
- 某运动APP登录协议分析
- 没了Ghost,系统也能“雨过天晴”了
- pandas用法-全网最详细教程
- Ubuntu16.04中好用的软件(持续更新)
- 威金病毒(viking)症状和治理方法
- 2022上半年朋友圈都在传的10本书,找到了
- laravel 将汉字转化成拼音的库
- 算法导论 — 比较排序算法对比实验
- science 计算机论文,计算机科学毕业论文
- 项目管理十大流程,让你轻松管理项目
- iOS和tvOS游戏按需加载资源简介
- SpringBoot---MongoDB的简单使用
- web页面设计的几个案例