Android常见问题解决方案Android开发Android开发经验谈

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

2017-12-23  本文已影响1045人  厘米姑娘

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


1.消息机制概述

a.作用:跨线程通信

b.常用场景:当子线程中进行耗时操作后需要更新UI时,通过Handler将有关UI的操作切换到主线程中执行。

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

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

c.四要素:

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

存在关系:

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

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

d.实现方法:

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


2.消息机制分析

a.工作流程:

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

b.工作原理:

//主线程中不需要自己创建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详解
 private Looper(boolean quitAllowed) {
       
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
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);
                }
            }
         ......   
    }

//第一种:send方式的Handler创建
Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                //如UI操作
                
            }
        };

//第二种:post方式的Handler创建
Handler handler = new Handler();

注意:创建Handler实例之前必须先创建Looper实例,否则会抛RuntimeException。

对于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()->MessageQueue.enqueueMessage() 最终将Message发送到MessageQueue。

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

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

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

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

现在,这里有一些有关消息机制的Questions,考考自己吧!


希望这篇文章对你有帮助~

上一篇下一篇

猜你喜欢

热点阅读