Looper类说明

   Looper 类用来为一个线程跑一个消息循环。

  线程在默认情况下是没有消息循环与之关联的,Thread类在run()方法中的内容执行完之后就退出了,即线程做完自己的工作之后就结束了,没有循环的概念。

  调用Looper类的 prepare() 方法可以为当前线程创建一个消息循环,调用loop() 方法使之处理信息,直到循环结束。

  大多数和消息循环的交互是通过 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类说明  

  Handler类用来发送和处理消息(Message)以及和线程的消息队列(MessageQueue)关联的Runnable对象。

  每一个Handler对象都仅和一个线程及这个线程的消息队列关联。

  一个特定线程的所有Handler对象都会收到同样的方法。(这是一个“一对多”的关系)。

  当你创建一个新的Handler对象,它会和创建它的这个线程/线程的消息队列绑定,从那个时刻开始,它将向这个消息队列传递消息和runnable对象,并且当它们从队列中出来时执行它们。

  Handler主要有两种用途:

  1.合理调度安排消息和runnable对象,使它们在将来的某个点被执行。

  2.将一个动作入队安排在非当前线程执行。

  调度消息是通过一系列的post方法和sendMessage方法。

  post方法允许你向消息队列中入队一些Runnable对象,在它们被接收到的时候会被调用,(实际上post方法也就是将runnable对象包装在消息里,然后再通过sendMessage方法实现),post方法有:

  post(Runnable r)

  postAtFrontOfQueue(Runnable r)

  postAtTime(Runnable r, Object token, long uptimeMillis)

  postAtTime(Runnable r, long uptimeMillis)

  postDelayed(Runnable r, long delayMillis)

  sendMessage方法允许你入队一个消息对象(Message),包含一个bundle数据,之后将会被Handler的handleMessage(Message)方法所处理。

  (这个需要你实现一个Handler的子类)。

  sendMessage方法有:

  sendEmptyMessage(int what)

  sendEmptyMessageAtTime(int what, long uptimeMillis)

  sendEmptyMessageDelayed(int what, long delayMillis)

  sendMessage(Message msg)

  sendMessageAtFrontOfQueue(Message msg)

  sendMessageAtTime(Message msg, long uptimeMillis)

  sendMessageDelayed(Message msg, long delayMillis)

  一个线程对应一个Looper,有一个消息队列,但是可以关联多个Handlers。

UI线程和非UI线程的通信

  当你的应用进程被创建的时候,应用进程的主线程(main thread)就建立一个消息队列,操纵top级别的应用对象(四大compotents比如activities、broadcast receivers等)和它们创建的任何窗口。

这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互。

  因为效率的考虑,所有的View和Widget的操作不是线程安全的,所以相关操作强制放在同一个线程,这样就可以避免多线程带来的问题。这个线程就是主线程,也即UI线程。

  你可以创建自己的线程,通过一个Handler对象和应用的主线程通信。

  如果你将一个Handler和你的UI线程连接,处理消息的代码就将会在UI线程中执行。

  新线程和UI线程的通信是通过从你的新线程调用和主线程相关的Handler对象的post或者sendMessage方法实现的,给定的Runnable或Message将会在Handler的消息队列中,并且在合适的时间被处理。

  总的来说,共有5种方式从非UI线程和UI线程通信:

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

  还有就是通过Handler,或者使用AsyncTask。

  具体参见之前的博文:http://www.cnblogs.com/mengdd/p/3418780.html

消息循环

  消息处理机制中,消息存放在一个消息队列中,而线程围绕这个队列进入一个无限循环,直到程序退出。

  如果队列中有消息,线程就会把消息取出来,并分发给相应的Handler进行处理;

  如果队列中没有消息,线程就会进入空闲等待状态,等待下一个消息的到来。

Android的主线程循环创建

  Android程序的运行入口点可以认为是android.app.ActivityThread类的main()方法(源码2.3.3):

    public static final void main(String[] args) {// other codes...// 创建主线程循环
        Looper.prepareMainLooper();if (sMainThreadHandler == null) {sMainThreadHandler = new Handler();}ActivityThread thread = new ActivityThread();thread.attach(false);// other codes...// 进入当前线程(此时是主线程)消息循环
        Looper.loop();// other codes...
thread.detach();// other codes...}

  这个main()方法里面为程序创建了主线程循环

  Looper类中的主线程创建方法prepareMainLooper()

    /*** Initialize the current thread as a looper, marking it as an application's* main looper. The main looper for your application is created by the* Android environment, so you should never need to call this function* yourself. {@link #prepare()}*/public static final void prepareMainLooper() {prepare();setMainLooper(myLooper());// other codes...}

  上面这个方法是专门为创建应用程序的主线程调用的,其他线程都不应该调用这个方法,而应该调用prepare()方法。

  主线程的Looper对象创建好之后会存在Looper类的成员变量mMainLooper里,通过一个get方法可以获取到:

    /*** Returns the application's main looper, which lives in the main thread of* the application.*/public synchronized static final Looper getMainLooper() {return mMainLooper;}

  这样之后,程序中其他线程就可以获取主线程的消息循环对象,从而和主线程通信。

线程创建消息循环:Looper.prepare()

  非主线程创建消息循环时,调用的是Looper类的prepare()方法,其实创建主线程的方法实质也调用了prepare方法:

    /*** Initialize the current thread as a looper. This gives you a chance to* create handlers that then reference this looper, before actually starting* the loop. Be sure to call {@link #loop()} after calling this method, and* end it by calling {@link #quit()}.*/public static final void prepare() {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper());}

  这个方法会调用Looper类的私有构造方法,创建Looper类对象。

    private Looper() {// 私有构造方法,在prepare()方法里面调用// 创建消息队列mQueue = new MessageQueue();mRun = true;// 当前线程mThread = Thread.currentThread();}

进入消息循环:Looper.loop()

  不管是不是主线程,prepare之后需要调用Looper类的loop()方法,可以看作是进入消息循环:

/*** Run the message queue in this thread. Be sure to call {@link #quit()} to* end the loop.*/public static final void loop() {// 进入当前线程的消息循环Looper me = myLooper();MessageQueue queue = me.mQueue;while (true) {// 从队列中取出消息Message msg = queue.next(); // might blockif (msg != null) {if (msg.target == null) {// No target is a magic identifier for the quit message.return;}// other codes...// 分发消息
                msg.target.dispatchMessage(msg);// 消息的target是Handler类型的对象// other codes...// 释放清理
                msg.recycle();}}}

消息分发和处理——Handler

  前面创建了消息循环,并且进入了这个循环,但是消息队列中的消息是如何加入和处理的呢?是通过Handler。

Handler构造:

  Handler有几个构造重载,如果构造时不提供Looper类对象参数,会获取当前线程的Looper对象,即将当前线程的消息循环作为Handler关联的消息循环。

  前面说过,不是所有线程都有一个消息循环,所以如果当前线程没有消息循环,而构造Handler对象时又没有指定Looper对象,则会抛出一个运行时异常

        mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}

  如果没有抛出异常,Handler对象构造好之后,它就关联了相应的Looper实例和消息队列实例,即完成绑定。

消息发送:

  Handler对象的post方法和sendMessage方法本质上都是发送消息的方法(post类方法实质上是调用了sendMessage方法)。

  所谓发送消息就是把消息放入消息队列中的合适位置,并且把消息的target设置为本Handler对象

  (这里将消息加入队列,也有一些什么线程唤醒的事儿咱们不深入讨论了)。

  可以添加,也就相应地有一些移除方法。

消息处理:

  在上面的Looper.loop()方法中,调用了消息对象target(即发送这个消息的Handler对象)的dispatchMessage()方法。

   /*** Handle system messages here.*/public void dispatchMessage(Message msg) {// 首先,处理Message自己的callback,调用其run方法if (msg.callback != null) {handleCallback(msg);}else {// 其次,调用Handler自留的接口对象// 这个成员变量声明时的注释如下:/*** Callback interface you can use when instantiating a Handler to* avoid having to implement your own subclass of Handler.*/if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}// 最后,调用handleMessage方法处理消息,Handler类中这个方法为空,子类可以重写这个方法
            handleMessage(msg);}}

  Handler类的handleMessage()方法默认实现为空:

    /*** Subclasses must implement this to receive messages.*/public void handleMessage(Message msg) {}

  上面的代码中也解释了为什么一个消息队列可以关联很多个Handler对象,因为虽然队列只有一个,但是消息的target是当时把它加入的Handler对象。

  所以当队列中的消息处理的时候,也会找到当时送它来的Handler对象,调用其相应的dispatchMessage()方法,进而调用其中的handleMessage()方法或者mCallback成员的handleMessage()方法来进行处理。

参考资料

  Handler:http://developer.android.com/reference/android/os/Handler.html

  Looper:http://developer.android.com/reference/android/os/Looper.html

  比较好的几个博文:

  Android应用程序线程消息循环模型分析:http://blog.csdn.net/luoshengyang/article/details/6905587

  Android应用程序消息处理机制(Looper、Handler)分析:http://blog.csdn.net/luoshengyang/article/details/6817933

  Android的消息队列模型:http://www.cnblogs.com/ghj1976/archive/2011/05/06/2038469.html

  Android中的Handler, Looper, MessageQueue和Thread:http://www.cnblogs.com/xirihanlin/archive/2011/04/11/2012746.html

  本博客其他相关博文:

  Android中的UI线程与非UI线程:http://www.cnblogs.com/mengdd/p/3418780.html

android 消息循环机制--looper handler相关推荐

  1. Android的消息处理机制——Looper,Handler和Message浅析

    题外话: 说来有些惭愧,对于这三者的初步认识居然是在背面试题的时候.那个时候自己接触Android的时间还不长,学习的书籍也就是比较适合入门的<疯狂Android讲义>,当然在学到Hand ...

  2. android 结束if循环_Android Handler 消息循环机制

    前言 一问起Android应用程序的入口,很多人会说是Activity中的onCreate方法,也有人说是ActivityThread中的静态main方法.因为Java虚拟机在运行的时候会自动加载指定 ...

  3. Android的消息循环机制:Handler

    前言 Android的消息机制主要是指Handler的运行机制,对于大家来说Handler已经是轻车熟路了,可是真的掌握了Handler?本文主要通过几个问题围绕着Handler展开深入并拓展的了解. ...

  4. android消息队列模型,Android 消息队列机制

    在非UI线程使用Handler进行线程通信时,一般都需要进行3个步骤: 创建Looper Looper.prepar() 创建Handler 启动消息循环Looper.loop() 通过这3步,基本就 ...

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

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

  6. Android 中Message,MessageQueue,Looper,Handler详解+实例

    一.几个关键概念 1.MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方.每一个线程最多只可以拥有一个MessageQueue数据结构. 创建一个线程的时候,并不会自 ...

  7. 详谈Windows消息循环机制

    一直对windows消息循环不太清楚,今天做个详细的总结,有说错的地方,请务必指出. 用VS2017新建一个win32 Application的默认代码如下: 这里有几个概念,容易混淆: 1.系统: ...

  8. Windows消息循环机制详细概述

    首先来了解几个基本概念: 消息:在了解什么是消息先来了解什么是事件.事件可分为几种,由输入设备触发的,比如鼠标键盘等等.由窗体控件触发的,比如button控件,file菜单等.还有就是来自Window ...

  9. android 消息提示机制

    消息提示机制 一 对话框 Dialog AlertDialog 对话框有:标准对话框, 菜单式对话框, 菜单式复选框对话框,自定义对话框 (注意:这里的上下文公用了,代码的点击方法我已经在点击监听事件 ...

最新文章

  1. 让PyTorch训练速度更快,你需要掌握这17种方法
  2. 近期活动盘点:基于雷达图像预测未来降水参赛经验分享、智慧政府讲座、金融AI思享会、数据法学研讨会(11.29-11.30)
  3. 老毛桃u盘启动pe重建mbr图文教程
  4. elasticsearch的映射(mapping)和分析(analysis)
  5. Linux vim中使用计算器
  6. 快评《19家网站内容低俗被曝光》
  7. 复现强网杯python is the best language 2
  8. 使用Arquillian测试安全的EJB
  9. 招聘 | 微生太高薪招聘多组学生信官(硕士及以上),月薪12k(北京为例),全国均可办公,推荐成功者奖励2000元...
  10. ansible笔记汇总
  11. freecodecamp_我在1个月内完成了整个freeCodeCamp课程(并记录了所有内容)
  12. SpringBoot使用CommandLineRunner和ApplicationRunner执行初始化业务
  13. Android 给TextView中的字体加上“中间线”
  14. MLDN Java学习笔记(3)
  15. oracle常见sql笔试题,一路SQL笔试题
  16. 常见的十大量化投资策略(附源码)
  17. Linux 打包压缩命令
  18. 什么是0day漏洞?
  19. 网络攻防|一次实战中的向日葵 RCE Bypass 360
  20. 后缀表达式(简单示例)

热门文章

  1. python调用函数传参时、有默认值的在中间 报错了_python的大坑:使用空列表作为默认参数,让我怀疑遇到了灵异代码...
  2. 单片机代码怎么读懂_单片机程序员的面试经验
  3. mysql批量修改http为https,墨涩网 - typecho系统升级全站https数据库批量替换网址/内容——墨涩网...
  4. c语言交换a b(运算符),关于编程语言:是否有一个复合赋值运算符用于a = b
  5. linux系统虚拟化测试,网络性能与磁盘测试 - Linux虚拟化性能PK:Ubuntu系统6大版本_Linux新闻_Linux公社-Linux系统门户网站...
  6. javascript onsubmit返回false仍然能提交_JavaScript对象-Get和Put
  7. Kotlin中的接口回调
  8. hcg值小于0.1_电容的Q值
  9. 16. Leetcode 845. 数组中的最长山脉 (数组-同向双指针-快慢指针)
  10. Leetcode 31. 下一个排列 (每日一题 20210831)