在android系统的应用程序中,与java程序相似,线程之间都是靠消息来驱动的,与此工作相关的是由handler,looper以及message,messagequene来完成。简单来说就是每一个线程中有且只有一个消息队列MessageQueue,利用looper来获取当前的线程和消息队列,我们可以不断向这个消息队列中添加消息Message,接着再利用handler从looper得知当前的消息队列,后再从中取出消息,处理消息。本文中代码示例参考了http://blog.csdn.net/smbroe/article/details/44239961中的代码并对其稍作改动。

什么是looper?looper里主要有两部分,一部分是线程,一部分是消息队列,一个looper就对应了一个当前的线程和当前线程下的消息队列。可以将looper比喻为工厂生产时用到的机械臂,不停地将从生产带上获取最新的产品(在消息列表中读取最新的消息),同时间最新的产品不停地打包(即将最新的消息不停地分发给handler),起着枢纽的作用。

我们通过一个简单的例子来学习如何使用Looper和Handler(handler的工作原理在下一篇博客中会讲,在这里只需大概理解为handler是发送消息队列中的消息并处理消息的就行了,本文只介绍下Looper),并通过这个例子来研究一下其工作原理;

首先,我们在LooperThread中为消息循环做准备,并创建一个Handler用于处理消息,注意Handler的创建要在调用Looper.prepare()之后,具体原因在等会会说明:

public class LooperThread extends Thread {public Handler mHandler;@Overridepublic void run() {// TODO Auto-generated method stubLooper.prepare();synchronized (this) {mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);Log.w("LooperThread", "handleMessage::Thread id---" + getId());}};}Looper.loop();notifyAll();}}

然后我们在主线程中创建一个新的线程,并通过新线程中的Handler向LooperThread线程发送消息;

 final LooperThread mLooperThread = new LooperThread();mLooperThread.start();new Thread() {@Overridepublic void run() {// TODO Auto-generated method stubwhile (mLooperThread.mHandler == null) {try {wait();//防止在发送消息时Handler还没建立} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}mLooperThread.mHandler.sendEmptyMessage(0);Log.w(TAG, "Send Message::Thread id ---" + getId());}}.start();

程序运行的结果如下:

可以看到线程之间通信成功了,下面我们再来审视整个过程,通过查看关键函数的源代码来去理解整个运作机制。

首先在LooperThreda中调用Looper.prepare()方法,我们查看其源代码:

public static void prepare() {prepare(true);}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));
}private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}

其中sThreadLocal就是looper里内置的数据管理类,里面存储着looper,定义如下

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

学过数据结构的同学应该很容易能根据其get(),set()方法想起链表,这里我就不对其多做分析了,总之就是用来存looper的数据结构罢了。接着是looper的构造器,从代码中我们可以看到主要就是新建一个消息队列并存于内部数据mQuene和获得当前的线程存于mThread,在这里消息队列和线程是相互绑定的,因此也验证了我们开头的结论,一个looper就对应了一个当前的线程和当前线程下的消息队列。回到示例代码中,接着就是新建了一个handler(代码中的扩展:synchronized是java里同步机制的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码,可以理解为两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码)
,并重写了handler的handleMessage方法用来对消息进行处理,这里我们先手动忽略这个方法一会再来分析。

接着调用Looper的loop方法。该方法实现了消息循环,源码如下:

  public static void loop() {//myLooper()方法就是通过sThreadLocal.get()返回我们刚刚设置的Looperfinal Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;// 确保线程和本地进程是一致的,并且记录这个identity tokenBinder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {Message msg = queue.next(); // 可能会阻塞if (msg == null) {// 没有消息则表明这个消息队列退出了.return;}// This must be in a local variable, in case a UI event sets the logger
//Printer表示打印事件Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}//分发该消息msg.target.dispatchMessage(msg);if (logging != null) {logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);}// 确保在分发的过程中该线程没有崩溃final long newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf(TAG, "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}msg.recycle();}}

这段代码中涉及到的知识比较多,我们只对与本文有关的关键方法进行讲解,其中通过mylooper()方法来获得刚在prepaer()方法中新建的looper,然后获得当前的消息队列,接着用一个for( ; ; )空循环来不断从消息队列中读取消息存于msg(msg=quene.next()),最后调用msg.target.dispatchMessage(msg)来讲消息分发出去,分发到哪里?分发到handler里交给它处理,有兴趣的同学可以先看看其源代码(具体分析下一篇才会讲):

 public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

可以看到最后又是通过调用我们重写的handleMessage来进行处理的。

接着是调用 notifyAll()来告诉等着调用被之前synchronized锁起来的代码的线程们,告诉它们我用完了,你们可以去抢着用了。

最后来看主线程中的示例代码中的 mLooperThread.mHandler.sendEmptyMessage(0);当我们调用了sendMessage方法之后就向Looper发送了一条消息,让我们看看这个方法,

消息是如何被传递的。sendMessage方法最终会调用到sendMessageAtTime方法来,来看看源代码:

ublic boolean sendMessageAtTime(Message msg, long uptimeMillis) {MessageQueue queue = mQueue;if (queue == null) {RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");Log.w("Looper", e.getMessage(), e);return false;}return enqueueMessage(queue, msg, uptimeMillis);}private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

可以看到,sendMessage方法最终调用了queue.enqueueMessage方法将消息加入到了Looper中的消息队列。那么整个线索就联系起来了,给handler

发消息,改消息到了looper的消息队列里,然后looper把这个消息取出来在交给looper来处理。这就是示例代码的整个运作过程,因此来总结一下吧。

1.首先是调用Looper.prepare()方法来创建一个新的队列和获取到当前的线程,

2.然后我们创建handler并重写其handleMessage方法,在我们构建handler的时候会获取到当前的looper对象(通过该looper对象来获取消息队列),消息队列和Callback对象(当然,在上述代码中Callback对象为null),紧接着我们在主线程里开的新线程中调用sendMessage方法来向handler中的消息队列来传递消息(当然,查看源代码可以知道其最终调用的是sendMessageAtTime方法,并通过返回enqueueMessage方法来讲消息加入到消息队列中),我们重写的handleMessage方法就是用来拦截我们感兴趣的消息并对消息进行处理的方法

3.最后是调用Looper.loop()来实现消息的循环分发,其通过queue.next()来不断获取消息队列中的最新消息并且调用 msg.target.dispatchMessage(msg)方法来实现消息的分发

4.最后是dispatchMessage方法实现消息的分发,在该方法中进行了一系列判断:

如果Message自带了Callback,则交给Message的Callback处理;

如果Handler了设置了Callback,则交给Handler的Callback处理;

如果两者都没有,则调用handleMessage方法处理(默认是不处理的)。

也可以参考下以下图片:

Android异步消息处理机制之looper机制相关推荐

  1. Android异步消息处理机制 深入理解Looper、Handler、Message三者关系

    转载子:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中 ...

  2. Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

    很多人面试肯定都被问到过,请问Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论. 1. 概述 ...

  3. Android异步消息处理机制 全解析

    Android异步消息处理机制主要是指Handler的运行机制以及Hanlder所附带的MessageQueue和Looper的工作过程. 本文将通过分析源码(api-28)的形式,全面解析Handl ...

  4. Android异步消息处理机制

    Android异步消息常用汇总 android常用异步框架分为handler.AsyncTask.handlerThread.IntentService. 什么是handler android消息机制 ...

  5. Android异步消息处理机制完全解析,带你从源码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9991569 之前也是由于周末通宵看TI3比赛,一直没找到时间写博客,导致已经有好久 ...

  6. [学习总结]6、Android异步消息处理机制完全解析,带你从源码的角度彻底理解

    开始进入正题,我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就有可能会崩溃.相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一 ...

  7. Android异步处理:Handler+Looper+MessageQueue深入详解

    为什么80%的码农都做不了架构师?>>> 转载自:http://blog.csdn.net/mylzc/article/details/6771331,在原文基础上修改整理再发布. ...

  8. Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析

    1.Handler的由来 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程. Android的UI操作并不是线程安全的 ...

  9. Android Handler 异步消息处理机制的妙用 创建强大的图片载入类

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 近期创建了一个群.方便大家交流,群号: ...

最新文章

  1. PAT(甲级)2020年秋季考试 7-4 Professional Ability Test
  2. 王洪超:WPF催熟整个软件生态链
  3. php mysql 检索跳转_jQuery+AJAX+PHP+MySQL数据库开发搜索功能,无跳转无刷新搜索。...
  4. Linux7如何手动建库,Centos 7系列删除数据库并重新安装
  5. 移动端通过ajax上传图片(文件)并在前台展示——通过H5的FormData对象
  6. 解决IntelliJ IDEA报错Error: java: 错误: 不支持发行版本 XX
  7. https 与 http
  8. 我国自主播放软件暴风影音挑落微软
  9. Java 算法 质因数2
  10. linux ls 目录结构,linux 系统目录结构 ls命令 文件类型 alias命令
  11. c++求数组中出现频率最高的数
  12. MySQL中的mysqldump命令使用详解
  13. 无源蜂鸣器c语言编程,电磁式蜂鸣器驱动原理与简单蜂鸣器编程及电路设计案例...
  14. java 邮件接收,用Java接收电子邮件
  15. 示波器的实时采样和等效采样
  16. 大数据可视化-Tableau
  17. Python获取高德POI(关键词搜索法)
  18. 交换机端口mtu值最大_mtu出现网络故障案例
  19. 高数_第3章重积分__二重积分_怎样交换积分次序
  20. matlab体会,Matlab心得体会

热门文章

  1. php google地图,google地图 标记地图代码
  2. Java 深入掌握JMS:JSM基础
  3. 虚拟地址,虚拟地址空间, 交换分区
  4. 在标准ASCII码表中,已知英文字母K的十六进制码值是4B,则二进制ASCII码1001000对应的字符是( )
  5. Python Matplotlib 散点图的绘制
  6. 芯盾时代:一种会思考的新一代安全身份认证方式
  7. 【Java并发】Java并发编程-02
  8. Jacoco-报告改造实践
  9. 3D打印美容设备MagicBox
  10. 软件定义网络 Software Defined Network (一)概述