前言

本篇文章介绍Android的消息机制,消息机制用于Android中的线程切换以及数据处理。所谓的消息机制,就是Handler的运行机制。Handler是消息机制的上层接口,我们开发中只需要使用Handler即可,除了Handler以外,底层还需要MessageQueueLooper的支持。还有一个类ThreadLocal也会介绍下,下面将介绍整个消息的运行机制。

目录

1、常见问题


1-1、Android为什么会有消息机制 ?

在Android中,特定的线程只能去完成一些特定的操作,比较典型场景就是,我们需要在子线程中进行耗时的I/O操作,可能是读取文件获取进行网络访问,当耗时操作完成以后需要在UI上进行改变,由于Android的限制,不能够在子线程中更新UI,这个时候就需要消息机制把更新UI操作切换到主线程去。


1-2、子线程为什么不能更新UI ?

在Android中,UI视图控件是线程不安全的,多个线程并发访问可能会导致UI控件出现异常。

那为什么不可以通过加锁来解决这个问题呢?

加锁缺点:加锁机制会让UI访问逻辑变得负责,其次是会降低UI的访问效率。


1-3、Looper内部无限循环为什么不会造成程序ANR ?

1-3-1、为什么会ANR?

一些耗时操作造成了主线程阻塞一定的时间,比如Activity在5s内不能响应用户事件,或者BroadcastReceiver的onReceive方法执行超过10s。

1-3-2、为什么Looper阻塞主线程却没有造成ANR?

主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。


2、重要角色

2-1、Handler 消息机制上层接口,用于发送接收处理消息

Handler通post()和sendMessage()方法发送消息。最终调用的都是enqueueMessage方法,就是向我们的消息队列中去插入此消息。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    msg.target = this;    if (mAsynchronous) {        msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}

Handler处理消息方法

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

2-2、Looper 消息轮询器,查询删除消息纷发给Handler处理

//创建Looper对象 Looper.prepare();//轮询器查询消息队列的消息 Looper.loop();

2-3、MessageQueue 消息队列,单链表存储消息

MessageQueue主要包含两个操作:插入和读取消息分别使用如下两个方法。使用单链表方式,对于插入和删除操作更加的方便。

boolean enqueueMessage(Message msg, long when) {} Message next(){  }

2-4、ThreadLocal 线程数据存储器

内部使用数组来模拟Map来存储线程的数据,数据存储后,只可以在指定的线程中获取到存储的数据。消息机制中存储的是当前线程的Looper对象。

3、源码解析

下面以主线程中创建Handler为例,来看下消息机制的源码,以及通过源码看整个系统的运行过程。

先看下Handler执行流程,更方便理解源码的执行流程。

Hanlder类:

步骤1、Handler-构造函数:

  public Handler(Callback callback, boolean async) {          if (FIND_POTENTIAL_LEAKS) {            final Class<? extends Handler> klass = getClass();            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&                    (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                    klass.getCanonicalName());            }        }        //看步骤2 ->  主线程中会自动创建Looper对象,这里获取Looper对象,由Looper循环消息纷发给Handler处理        mLooper = Looper.myLooper();        // 没有Looper对象会抛异常        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        // 消息队列MessageQueue对象 作为Looper的成员变量        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

步骤5、Handler纷发消息,并处理消息(自己实现)

  public void dispatchMessage(Message msg) {          if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            //  处理消息            handleMessage(msg);        }    }  /**     * 系统处理消息为空方法,这里使用时要重写该方法     */    public void handleMessage(Message msg) {        }

上面2-1介绍,Handler发送消息时,是向MessageQueue队列中插入消息

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        // 向消息队列中插入消息并且返回是否插入成功        return queue.enqueueMessage(msg, uptimeMillis);    }

Looper类:

我们知道在主线程中创建Handler对象,系统默认创建Looper对象,以及执行Looper.prepare(),和Looper.loop()方法,就是说主线程中是默认有Looper对象的。

步骤2、Looper 初始化,创建Handler时候调用

// 创建Looper对象,并存到当前线程的ThreadLocal中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));   }// 从ThreadLocal中获取当前线程的Looper对象public static @Nullable Looper myLooper() {     return sThreadLocal.get(); }// 用于存储Looper的TreadLocal对象static final ThreadLocal sThreadLocal = new ThreadLocal();

步骤3、Looper轮询器不断查询消息队列中消息

 public static void loop() { // 获取Looper对象        final Looper me = myLooper();        // 没有Looper对象  抛异常        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final MessageQueue queue = me.mQueue;                ...................省略        for (;;) {        // 轮询消息队列 不断的取消息            Message msg = queue.next(); // might block                        // 当消息队列中没有消息时候,跳出无限循环            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }    .......................省略                     try {                        //步骤5 -> msg.target就是Handler对象,纷发消息                msg.target.dispatchMessage(msg);                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            } finally {                        ........................省略                         msg.recycleUnchecked();        }    }

4、消息机制在Android中应用

Android中用到消息机制的最常用的就是AsnycTask,一个异步任务执行框架。大家可以移步这篇博客。

Android多线程系列(一) AsyncTask基本使用以及源码解析

更多相关文章

  1. Android(安卓)GWES分析
  2. 关于android中使用new Message的内存泄露问题
  3. Android消息机制
  4. android中Invalidate和postInvalidate的区别
  5. Android线程优先级设置方法
  6. Android(安卓)Handler
  7. Handler机制分析
  8. Android简明开发教程十九:线程 Bezier曲线
  9. Android异步处理常用方法

随机推荐

  1. 路由和视图原理与实现
  2. Android弹性收缩自适应布局FlexboxLayout
  3. android 数据传输之JSON
  4. Android(安卓)图片的帧动画
  5. 关于Android(安卓)ListView组件中android
  6. Android的Message机制
  7. Android(安卓)Toolchain与Bionic Libc
  8. Android(安卓)8.1隐藏状态栏图标
  9. Windows环境下Android(安卓)Studio v1.0
  10. Android(安卓)的OpenGL ES与EGL