要点提炼|开发艺术之消息机制

Android的消息机制指的是Handler的运行机制,本篇将总结Handler机制的相关知识点:

  • 消息机制概述
  • 消息机制分析

1.消息机制概述html

a.做用:跨线程通讯android

b.经常使用场景:当子线程中进行耗时操做后须要更新UI时,经过Handler将有关UI的操做切换到主线程中执行。安全

系统不建议在子线程访问UI的缘由:UI控件非线程安全,在多线程中并发访问可能会致使UI控件处于不可预期的状态。而不对UI控件的访问加上锁机制的缘由有:bash

  • 上锁会让UI控件变得复杂和低效
  • 上锁后会阻塞某些进程的执行

c.四要素:数据结构

  • Message(消息):须要被传递的消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,最终由Handler处理。
  • MessageQueue(消息队列):用来存放Handler发送过来的消息,内部经过单链表的数据结构来维护消息列表,等待Looper的抽取。
  • Handler(处理者):负责Message的发送及处理。
    • Handler.sendMessage():向消息池发送各类消息事件。
    • Handler.handleMessage()处理相应的消息事件。
  • Looper(消息泵):经过Looper.loop() 不断地从MessageQueue中抽取Message,按分发机制将消息分发给目标处理者。

Thread(线程):负责调度整个消息循环,即消息循环的执行场所。多线程

存在关系:并发

  • 一个Thread只能有一个Looper,能够有多个Handler;
  • Looper有一个MessageQueue,能够处理来自多个Handler的Message;
  • MessageQueue有一组待处理的Message,这些Message可来自不一样的Handler;
  • Message中记录了负责发送和处理消息的Handler;
  • Handler中有Looper和MessageQueue;

关系

数量关系

图片来源android的消息处理机制之Looper,Handler,Message异步

d.实现方法:ide

  • 在主线程实例化一个全局的Handler对象;
  • 在须要执行UI操做的子线程里实例化一个Message并填充必要数据,调用Handler.sendMessage(Message msg)方法发送出去;
  • 复写handleMessage()方法,对不一样Message执行相关操做;

实例:Service篇--异步消息处理机制函数


2.消息机制分析

a.工做流程:

  • Handler.sendMessage()发送消息时,会经过MessageQueue.enqueueMessage()向MessageQueue中添加一条消息;
  • 经过Looper.loop()开启循环后,不断轮询调用MessageQueue.next()
  • 调用目标Handler.dispatchMessage()去传递消息,目标Handler收到消息后调用Handler.handlerMessage()处理消息。

简单来看,即HandlerMessage发送到Looper的成员变量MessageQueue中,以后Looper不断循环遍历MessageQueue从中读取Message,最终回调给Handler处理。如图:

b.工做原理:

  • (1)Looper的建立:先从应用程序的入口函数ActivityThread.main()看起,在这里(主线程)系统自动建立了Looper,主要方法:
//主线程中不须要本身建立Looper
public static void main(String[] args) {
        ......
        Looper.prepareMainLooper();//为主线程建立Looper,该方法内部又调用 Looper.prepare()
        ......
        Looper.loop();//开启消息轮询
        ......
        
    }
复制代码

注意

  • 子线程的Looper须要手动去建立,标准写法是:
//子线程中须要本身建立一个Looper
new Thread(new Runnable() {
            @Override
            public void run() {
                
                Looper.prepare();//为子线程建立Looper               
                Looper.loop(); //开启消息轮询
            }
        }).start();
复制代码
  • 不管是主线程仍是子线程,Looper只能被建立一次,即一个Thread只有一个Looper。
  • 所建立的Looper会保存在ThreadLocal(线程本地存储区)中,它不是线程,做用是帮助Handler得到当前线程的Looper。更多讲解见ThreadLocal详解
  • (2)MessageQueue的建立:在Looper的构造函数建立了一个MessageQueue:
private Looper(boolean quitAllowed) {
       
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
复制代码
  • (3)Message轮询及处理:有了Looper和MessageQueue以后经过Looper.loop()开启消息轮询
public static void loop() {
        ......
        for (;;) {//死循环
            Message msg = queue.next(); //用于提取下一条信息,该方法里一样有个for(;;)死循环,当没有可处理该Message的Handler时,会一直阻塞
            if (msg == null) {
                
                return;
            }
         ......   
         try {
                msg.target.dispatchMessage(msg);//若是从MessageQueue中拿到Message,由和它绑定的Handler(msg.target)将它发送到MessageQueue
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
         ......   
    }

复制代码
  • 如今就剩建立Handler及Message发送了。(4)先看Handler的建立:有两种形式的Handler:
//第一种:send方式的Handler建立
Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                //如UI操做
                
            }
        };

//第二种:post方式的Handler建立
Handler handler = new Handler();
复制代码

注意:建立Handler实例以前必须先建立Looper实例,不然会抛RuntimeException。

  • (5) Message的发送:

对于send方式的Handler:建立好一个Message后,调用Handler的如下几种常见的方法来发送消息:

sendEmptyMessage();           //发送空消息
sendEmptyMessageAtTime();     //发送按照指定时间处理的空消息
sendEmptyMessageDelayed();    //发送延迟指定时间处理的空消息
sendMessage();                //发送一条消息
sendMessageAtTime();          //发送按照指定时间处理的消息
sendMessageDelayed();         //发送延迟指定时间处理的消息
sendMessageAtFrontOfQueue();  //将消息发送到消息队头
复制代码

对于post方式的Handler,可在子线程直接调用Handler的如下几种常见方法,使得切换到主线程:

post(Runnable r)
postAtFrontOfQueue(Runnable r)
postAtTime(Runnable r, Object token, long uptimeMillis)
postAtTime(Runnable r, long uptimeMillis)
postDelayed(Runnable r, long delayMillis)

//例如,postDelayed()方法
handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //如UI操做
                    }
                },300);

复制代码

经过以上各类Handler的发送方法,都会依次调用 Handler.sendMessageDelayed->Handler.sendMessageAtTime()->Handler.enqueueMessage() 最终将Message发送到MessageQueue。

至此从源码已走过一遍流程。

推荐阅读:深刻了解Android的消息机制(源码)

最后,将Handler机制汇总到一张图:

图片来源android的消息机制——Handler机制

如今,这里有一些有关消息机制的Questions,考考本身吧!


但愿这篇文章对你有帮助~

相关文章
相关标签/搜索