• Android 消息机制(Handler,Looper,MessageQueue,Message)


      android的消息处理有三个核心类:Looper,Handler和Message。其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,Handler扮演了往MQ上添加消息和处理消息的角色(只处理由自己发出的消息),即通知MQ它要执行一个任务(sendMessage),并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。

       消息处理过程如下图所示:

     

    Handler主要涉及到的内容有:

      Handler 、 Handler.CallbackAsyncQueryHandler

      Looper

      HandlerThreadRunnable

      MessageMessage queue

    Looper

    Android官方文档中Looper的介绍:

    Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

    Most interaction with a message loop is through the Handler class.

    This is a typical example of the implementation of a Looper thread, using the separation of prepare() and loop() to create an initial Handler to communicate with the Looper.

    View Code
     1 class LooperThread extends Thread {
     2 
     3       public Handler mHandler;
     4 
     5       public void run() {
     6 
     7           Looper.prepare(); 
     8 
     9           mHandler = new Handler() {
    10 
    11               public void handleMessage(Message msg) {
    12 
    13                   // process incoming messages here
    14 
    15               }
    16 
    17           };
    18 
    19           Looper.loop();
    20 
    21       }
    22 
    23 }

    Android中的Looper类,是用来封装消息循环和消息队列的一个类,用于在android线程中进行消息处理。handler其实可以看做是一个工具类,用来向消息队列中插入消息的。

    (1) Looper类用来为一个线程开启一个消息循环。

    默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

    (2) 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。

    默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。

    mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).

    Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

    (3) 在非主线程中直接new Handler() 会报如下的错误:

    E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception

    E/AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

    原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。

    (4) Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。

    注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

    (5) 基于以上知识,可实现主线程给子线程(非主线程)发送消息。

    将代码中的mHandler声明成类成员,在主线程通过mHandler发送消息即可。

     

    Handler

      Handler在android里负责发送和处理消息。它的主要用途有:

      1)按计划发送消息或执行某个Runnanble(使用POST方法);

      2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)

       默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

        调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列;sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列,然后交由handleMessage(Message)方法处理。(这个需要你复写Handler的handleMessage方法)。

    1.Handler使用post方法

    View Code

    程序运行结果为:

           从结果可以看出,使用post方法是将一个Runnable对象依附在主线程上面,并没有开启一个新的线程。注意:如果在Runnable对象中执行耗时的操作的话,还是会弹出ANR对话框。

    2.Handler使用sendMessage方法

        sendMessage有多种方式:

    (一)     Handler和sendMessage都在同一个线程里面

    (二)     Handler在主线程,sendMessage在子线程

    (三)     Handler在子线程,sendMessage在主线程

    对于第一种情况,就是在创建Handler对象的时候重写handleMessage()方法,还是使用的是主线程,所以在处理消息中不能有耗时操作,否则会出现ANR对话框。

    对于第二种情况,创建了一个新的线程,可以处理耗时操作,示例代码如下:

    View Code

      对于第三种情况,就要涉及到HandlerThread。由于在默认情况下,Handler接受的是当前线程下的消息循环实例,要使用子线程的消息队列,就得使用HandlerThread,它继承于Thread,与普通Thread的差别在于,它有一个Looper成员变量,这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是消息队列+消息循环。(当我们需要一个工作线程时,而不是把它当作一次性消耗品,用过即废弃的话,就可以使用HandlerThread)。

    HandlerThread

      Android官方文档中Looper的介绍:

       Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called. 

    HandlerThread源代码中的run方法代码如下:

    public void run() {
            mTid = Process.myTid();
            Looper.prepare();  //使该线程拥有一个Looper对象
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();  //让Looper开始工作,从消息队列里取消息,处理消息
            mTid = -1;
    }

    继承了该类的Thread就拥有了Looper成员变量,可以处理Handler发送的消息。

    View Code                                                                                                                                  

    程序运行结果如下:

  • 相关阅读:
    Plug It In
    The King's Walk
    Water Testing 匹克定理
    基尔霍夫矩阵
    nginx 常用的命令
    Nginx window安装
    使用nrm管理 npm 镜像仓库
    window 安装node.js
    变量和数据类型
    同步,异步,阻塞,非阻塞
  • 原文地址:https://www.cnblogs.com/adm1989/p/2799818.html
Copyright © 2020-2023  润新知