关于android:知乎1578赞Android-中为什么需要-Handler

2次阅读

共计 5543 个字符,预计需要花费 14 分钟才能阅读完成。

要了解 Handler,就得先了解 Android 的 Message 机制.

这里以用户滑动微信朋友圈为例,解说一下 Android 的 Message 机制是怎么运行的,Message 机制中的各个外围组件都做了什么

Message 产生

用户滑动屏幕,产生了一系列 input 事件(一个 Down 事件,若干个 Move 事件,一个 Up 事件),这些事件被零碎包装成了一系列 Message(一个 Down Message,若干个 Move Message,一个 Up Message)

Message 是用来传递信息的,上述 Message 中就蕴含了这些 input 事件的信息,比方 x 坐标,y 坐标。

MessageQueue 寄存 Message

Message 产生后,有一个问题就是这些 Message 怎么发给利用?我要滑动朋友圈,那么这些个 Message 就得传给微信,让微信去解决,微信将这些事件给到朋友圈的 List 控件,让 List 产生新内容,并且实现高低滑动。

首先想到的能不能间接把这些 Message 给到朋友圈的 List 控件(SystemServer 能够间接 Binder 发给 List 控件),能够是能够,然而麻烦;SystemServer 间接给朋友圈的 List 控件发 input message,那 SystemServer 得先晓得有这么个控件,问题是利用有哪些控件,SystemServer 是不晓得的,难道要遍历所有的控件,每个控件都发一个反复的 Message?这显然不是咱们想要的。

SystemServer 不能间接发给控件,那么能不能间接发给利用,让利用本人去解决呢?答案是必定的,当初的 Android 也是这么做的,你利用筹备一个 MessageQueue(音讯队列),我有 Message 就放到这个 MessageQueue 外面,你利用本人去解决,岂不美哉,这就是 MessageQueue 呈现的起因

Looper 派发 Message

利用筹备了一个 MessageQueue 之后,SystemServer 把之前包装好的一系列 Input Message(一系列 Message(一个 Down Message,若干个 Move Message,一个 Up Message))放到了微信的 MessageQueue 外面,剩下的就让微信本人去读取 MessageQueue 外面的内容,本人更新 UI 去

问题是 MessageQueue 只是用来寄存 Message 的,得有人来治理这个 MessageQueue。比方 MessageQueue 外面进了几个 Message,这些 Message 该到发给谁去解决?

这里就引入了 Looper,Looper 来决定这个 Message 该发给谁去解决,Looper 会依照 Message 在 MessageQueue 外面的程序,一个一个取出 Message,依据 Message 自带的信息(我想被谁解决 – target),发给对应的人去解决

这个例子外面,这些 Message 的 target 就是微信的主线程的 handler

Handler 解决 Message

这时候,Handler 出场了,下面说 Looper 把 Message 发给对应的人去解决,这个 就是 Handler。Handler 就是用来解决 Message 的,作为 Message 机制的最初一环,Handler 读取 Message 内容后,依据内容来做相干的解决。

这个例子外面,一系列 Input Message 最终会由微信的主线程 Handler 来解决,通过简单的事件传递和事件散发流程,传给对应的 List 控件,List 控件依据 Input Message 外面的内容,计算出本人下一帧的各个 Item 的地位,更新本人的 Item 和 Item 内的内容,从而产生 List 滑动成果,朋友圈滑动的流程就实现了

Message 机制总结

有了下面的 Message 机制的案例,了解上面这张图就牵强附会了,如下面几个题目所示

  1. Message 承载内容
  2. MessageQueue 寄存 Message
  3. Looper 派发 Message
  4. Handler 解决 Message

App 主线程

那么,App 主线程是怎么回事?上面是 App 过程创立后,ActivityThread.main 办法被调用的逻辑

frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
       ......
       // 创立 Looper、Handler、MessageQueue
       Looper.prepareMainLooper();
       ......
       ActivityThread thread = new ActivityThread();
       thread.attach(false, startSeq);

       if (sMainThreadHandler == null) {
           // 指定主线程的 handler 为 H
           sMainThreadHandler = thread.getHandler();}
       ......
       // 开始筹备接管音讯
       Looper.loop();}
}

// 筹备主线程的 Looper
frameworks/base/core/java/android/os/Looper.java
public static void prepareMainLooper() {prepare(false);
    synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();}
}

// prepare 办法中会创立一个 Looper 对象
frameworks/base/core/java/android/os/Looper.java
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));
}

// Looper 对象创立的时候,同时创立一个 MessageQueue
frameworks/base/core/java/android/os/Looper.java
private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();}

通过下面的流程,主线程的 Looper、MessageQueue 都曾经创立好了,这就打下了 Message 机制的根底,后续有 Message 进来,就会进入主线程的 MessageQueue,而后 Looper 会把他派发给对应的 Handler

对于主线程来说,这个 Handler 就在 ActivityThread 外面,上面截取一小段 Handler 的办法,大家能够看一下,相熟代码的应该晓得,BIND_APPLICATION 就是大家常常在 Systrace 中看到的新过程启动时候的那一段

frameworks/base/core/java/android/app/ActivityThread.java
class H extends Handler {
    public static final int BIND_APPLICATION        = 110;
    public static final int EXIT_APPLICATION        = 111;
    public static final int RECEIVER                = 113;
    public static final int CREATE_SERVICE          = 114;
    public static final int SERVICE_ARGS            = 115;
    public static final int STOP_SERVICE            = 116;

    public void handleMessage(Message msg) {switch (msg.what) {
            case BIND_APPLICATION:
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                AppBindData data = (AppBindData)msg.obj;
                handleBindApplication(data);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                break;
        }
    }
}

所以之前也有人会问,ActivityThread 是主线程么?为什么没有继承 Thread?看了下面的流程,答案就很分明了,ActivityThread 并不是一个 Thread,只不过他有个叫 H 的 Handler 来解决主线程的 Message 而已;另外 Activity、Service、BroadcastReceiver 组件的生命周期都是在主线程执行的,通过下面的解说应该就比拟好了解了:都是在 ActivityThread 的 H 这个 Handler 外面解决的.

线程间通信

App 主线程初始化实现后,Message 机制跑起来了,那么子线程呢?其实也是一样的,子线程也有一套 Message 机制,有它本人的 MessageQueue、Looper、Handler。

那么线程间的 Message 通信就好了解了,Looper 在派发 Message 的时候,会依据 Message 本人的志愿(target,即指标 Handler),派发给对应的 Handler 去解决,这里的 Handler 既能够是子线程的 Handler,也是主线程的 Handler,也能够是 App 过程外面其余的 Handler,只有晓得且指定这个 Handler 即可

比方十分典型的一个例子就是 AsyncTask,如果你在主线程创立了 AsyncTask,那么在 AsyncTask 执行在子线程完耗时工作后,就会给主线程的 Handler 发 Message,来更新主线程的 UI

子线程能不能更新 UI

既然主线程和子线程都是 Message 机制,子线程到底能不能更新 UI 呢?答案是能够的,然而会出问题,比方主线程正在执行 doFrame,Measure 办法刚刚走完,你子线程把 View 的宽高给改掉了,那么主线程后续执行 Layout 的时候,View 的地位摆放就可能会出问题(当然我没有试过,感兴趣的小伙伴能够把 checkThread 限度代码去掉,而后在子线程更新 UI 试试)

所以 Android 为了防止这种状况,在有 UI 更新的中央,都加了 checkThread(),来确保只有主线程能力更新 UI

    void checkThread() {if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException("Only the original thread that created a view hierarchy can touch its views.");
        }
    }

最初

对于如何学习 Android Framework 开发常识,最近有幸在前阿里技术总监手里扒到这份 Android framework 高级开发笔记,明天就拿进去分享给大家。

本笔记解说了 Framework 的次要模块,从环境的部署到技术的利用,再到我的项目实战,让咱们不仅是学习框架技术的应用,而且能够学习到应用架构如何解决理论的问题,由浅入深,具体解析 Framework,让你简略高效学完这块常识!

如有须要获取残缺的材料文档的敌人能够【点击我】收费获取。

第一章:深刻解析 Binder

Binder 机制作为过程间通信的一种伎俩,基本上贯通了 andorid 框架层的全副。所以首先必须要搞懂的 Android Binder 的根本通信机制。Binder 机制作为过程间通信的一种伎俩,基本上贯通了 andorid 框架层的全副。所以首先必须要搞懂的 Android Binder 的根本通信机制。

本章知识点

  • Binder 系列—开篇
  • Binder Driver 初探
  • Binder Driver 再探
  • Binder 启动 ServiceManager
  • 获取 ServiceManager
  • 注册服务(addService)
  • 获取服务(getService)
  • Framework 层剖析
  • 如何应用 Binder
  • 如何应用 AIDL
  • Binder 总结
  • Binder 面试题全解析

第二章:深刻解析 Handler

本章先宏观实践剖析与 Message 源码剖析,再到 MessageQueue 的源码剖析,Looper 的源码剖析,handler 的源码剖析,Handler 机制实现原理总结。最初还整顿 Handler 所有面试题大全解析。

Handler 这章内容很长,但思路是循序渐进的,如果你能保持读完我置信必定不会让你悲观。

本章知识点

  • 宏观实践剖析与 Message 源码剖析
  • MessageQueue 的源码剖析
  • Looper 的源码剖析
  • handler 的源码剖析
  • Handler 机制实现原理总结
  • Handler 面试题全解析

第三章:Dalvik VM 过程零碎

Andorid 系统启动、init 过程、Zygote、SystemServer 启动流程、应用程序的创立应用,Activity 的创立、销毁 Handler 和 Looper。

第四章 深刻解析 WMS

窗口治理框架 零碎动画框架 View 的工作原理。

第五章 PackagerManagerService

包治理服务,资源管理相干类。

如有须要获取残缺的材料文档的敌人能够【点击我】收费获取。

正文完
 0