知乎1578赞:Android-中为什么需要-Handler-(2)

这里就引入了 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

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 面试题全解析

最后,面试前该准备哪些资源复习?

其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

这里再分享一下我面试期间的复习路线:(以下体系的复习资料是我从各路大佬收集整理好的)

《Android开发七大模块核心知识笔记》

面试字节两轮后被完虐,字节面试官给你的技术面试指南,请查收

面试字节两轮后被完虐,字节面试官给你的技术面试指南,请查收

《960全网最全Android开发笔记》

面试字节两轮后被完虐,字节面试官给你的技术面试指南,请查收

《379页Android开发面试宝典》

历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值