当前位置: 首页 > news >正文

Android面试题精选——再聊Android-Handler机制

static final ThreadLocal sThreadLocal = new ThreadLocal();

//创建当前线程的Looper对象
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对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}

这里有一个很关键的类:ThreadLocal,它一个线程内部的数据存储类,通过它存储的数据只有在它自己的线程才能获取到,其他线程是获取不到的。所以sThreadLocal.get()获取的就是当前线程的Looper对象。在Looper.prepare()方法中我们看到了如果当前线程已经有Looper对象,就会抛出异常,说一个线程只能创建一个Looper对象,所以Looper对象与自己所在的线程是相对应的。
再看Looper的构造方法:

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

Looper的构造方法是私有的,外界不能直接创建Looper对象,只能通过Looper.prepare()方法创建对象并且通过Looper.myLooper()获取对象,这就保证了一个线程只能有一个Looper对象。Looper.prepare()不能调用两次。

在Looper的构造方法中会创建一个MessageQueue对象,这个就是负责存放消息的消息队列,也就是Handler所持有的mQueue 对象。它是由Looper创建和管理的。

看完了Handler、Looper和MessageQueue对象的创建,接着看消息的发送:

Handler发送消息的方法有很多,但无论你是send一个Message还是post一个Runnable;无论你是延时发送还是不延时发送,最终都会调用Handler的enqueueMessage()方法。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//把this赋值给msg的target属性,this就是Handler对象。
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//把消息存放到MessageQueue
return queue.enqueueMessage(msg, uptimeMillis);
}

这里直接把消息存放到MessageQueue 就完事了。那么消息又是从哪里被取出来的呢?
Looper里有一个Looper.loop()方法,我们看一下它的源码。

public static void loop() {

final MessageQueue queue = me.mQueue;
//一个死循环
for (;😉 {
//从MessageQueue中取出一条消息
Message msg = queue.next();
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//把消息交给Handler处理。
msg.target.dispatchMessage(msg);
}
}

从上面的代码中我们看到loop()会开启一个死循环,不断地从MessageQueue中取出消息并交给Handler处理。在前面的enqueueMessage()方法中我们知道了msg.target就是发送消息的Handler对象。

这里有同学可能会有疑问:上面的代码中明明如果(msg == null),就退出方法,为什么我还说loop()里面是个死循环呢?这是因为MessageQueue的next()方法取出消息的时候,如果没有消息,next()方法会阻塞线程,直到MessageQueue有消息进来,然后取出消息并返回。所以queue.next()一般不会返回null,除非调用Looper的quit()或者quitSafely()方法结束消息轮询,queue.next()才会返回null,才会结束循环。

public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}

最后我们来看 一下消息的处理:Handler的dispatchMessage(msg)方法。

public void dispatchMessage(Message msg) {
//如果Message有自己的callback,就由Message的callback处理
if (msg.callback != null) {
handleCallback(msg);
} else {
//如果Handler有自己的mCallback,就由Handler的mCallback处理
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//默认的处理消息的方法
handleMessage(msg);
}
}

处理消息的方法有三个:

1、优先级最高的是Message自己的callback,这是一个Runnable对象,我们用Handler post一个Runnable的时候,其实就是把这个Runnable赋值个一个Message对象的callback,然后把Message对象发送给MessageQueue。
2、优先级第二的是Handler自己的mCallback,在我们创建一个Handler对象的使用可以传一个Handler.Callback对象给它并实现Callback里的handleMessage(msg)方法,作为我们的消息处理方法。
3、优先级最低的是Handler自己的handleMessage(msg)方法,这也是我们最常用的消息处理方法。

到这里我们的分析就结束了,现在你对Handler机制是不是有了深刻的认识呢。

不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊~

今天讲的只是Handler机制一方面,最后文末这里还有我一路学习以来收集整理理出来的各个大厂面试题资料,其中有些面试题是我自己多次面试整理出来的面试题,在这里免费分享给我的粉丝们以及读者们,需要的伙伴们快来领取吧~

#####领取方式: 关注【我的主页】获取免费领取方式~

或者加入我的技术群887084983 获取一下 ~

面试:如果不准备充分的面试,完全是浪费时间,更是对自己的不负责!

金九银十面试季,赶快去为自己的面试做足准备吧!

最后,祝愿大家都能找到一份好的工作,拿到心仪的offer!

以下墙裂推荐阅读!!!
  • Android学习笔记参考(敲黑板!!)
  • “寒冬未过”,阿里P9架构分享Android必备技术点,让你offer拿到手软!
  • 毕业3年,我是如何从年薪10W的拖拽工程师成为30W资深Android开发者!
  • 腾讯T3大牛带你了解 2019 Android开发趋势及必备技术点!
  • 八年Android开发,从码农到架构师分享我的技术成长之路,共勉!

如果你觉得还算有用的话,不妨把它们推荐给你的朋友~

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

[外链图片转存中…(img-duRxDEj6-1719086436047)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

相关文章:

  • 分类接口开发
  • [SAP ABAP] 排序内表数据
  • 计组--存储系统--复习专用...
  • 【iOS】#include、#import、@class、@import
  • 2024广东省职业技能大赛云计算赛项实战——Minio服务搭建
  • CTFHUB-SSRF-端口扫描
  • DDMA信号处理以及数据处理的流程---cfar检测
  • 【database3】oracle:数据交换/存储/收集
  • Vite: 关于静态资源的处理机制
  • 计算机组成原理 —— 存储系统(DRAM和SRAM,ROM)
  • Typora Markdown编辑器 for Mac v1.8.10 安装
  • SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测
  • 图像数字化基础
  • python实现无人机航拍图片像素坐标转世界坐标
  • go语言:数据库sql查询保存任意数量字段的数据
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • Android交互
  • C++类中的特殊成员函数
  • IndexedDB
  • JavaScript对象详解
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • October CMS - 快速入门 9 Images And Galleries
  • Promise初体验
  • 分布式事物理论与实践
  • 给github项目添加CI badge
  • 三栏布局总结
  • 实现菜单下拉伸展折叠效果demo
  • 手机端车牌号码键盘的vue组件
  • 问题之ssh中Host key verification failed的解决
  • 终端用户监控:真实用户监控还是模拟监控?
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 阿里云ACE认证学习知识点梳理
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • ![CDATA[ ]] 是什么东东
  • #define 用法
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (3)llvm ir转换过程
  • (3)STL算法之搜索
  • (java)关于Thread的挂起和恢复
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (三)模仿学习-Action数据的模仿
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • .form文件_一篇文章学会文件上传
  • .NET MVC 验证码
  • .Net Remoting(分离服务程序实现) - Part.3
  • .NET 材料检测系统崩溃分析
  • .NET 直连SAP HANA数据库
  • .NET与 java通用的3DES加密解密方法
  • /proc/stat文件详解(翻译)
  • [100天算法】-实现 strStr()(day 52)