Android Handler相关面试题你能答对多少?子线程和主线程是如何切换的?

Trace.traceEnd(traceTag);

}

}

msg.recycleUnchecked();

}

}

这是循环消息时的部分代码,处理消息代码是msg.target.dispatchMessage(msg);,这里的target就是当时发送消息的handler。

3.在子线程发送消息,却能够在主线程接收消息,主线程和子线程是怎么样切换的?

子线程用handler发送消息,发送的消息被送到与主线程相关联的MessageQueue,也是主线程相关联的Looper在循环消息,handler所关联的是主线程的Looper和MessageQueue,所以最后消息的处理逻辑也是在主线程。只有发送消息是在子线程,其它都是在主线程,Handler与哪个线程的Looper相关联,消息处理逻辑就在与之相关的线程中执行,相应的消息的走向也就在相关联的MessageQueue中。所以子线程切换到主线程是很自然的过程,并没有想象中的复杂。

4.能不能在子线程中创建Handler?

可以,但是在创建前先调用prepare()方法创建Looper。Handler创建的时候,会去检查是否有创建Looper,如果没有创建就会抛出异常。相关源码如下:

public Handler(Callback callback, boolean async) {

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can’t create handler inside thread " + Thread.currentThread()

  • " that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

所以我们在子线程需要先调用prepare()方法创建Looper。这里还多提一点,在主线程创建就不需要自己创建Looper,因为在ActivityTread类里面,已经为我们创建好了,相关源码如下:

public static void main(String[] args) {

Looper.prepareMainLooper();// 为主线程创建looper

// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.

// It will be in the format “seq=114”

long startSeq = 0;

if (args != null) {

for (int i = args.length - 1; i >= 0; --i) {

if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {

startSeq = Long.parseLong(

args[i].substring(PROC_START_SEQ_IDENT.length()));

}

}

}

ActivityThread thread = new ActivityThread();

thread.attach(false, startSeq);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread.getHandler();

}

if (false) {

Looper.myLooper().setMessageLogging(new

LogPrinter(Log.DEBUG, “ActivityThread”));

}

// End of event ActivityThreadMain.

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

Looper.loop();

throw new RuntimeException(“Main thread loop unexpectedly exited”);

}

Looper.prepareMainLooper();这句代码就是为主线程创建Looper。 所以在主线程中直接创建一个Handler,就直接可以循环消息,因为安卓的主线程已经为我们准备好了Looper。

5.一个线程可以有几个Handler?几个Looper?

一个线程可以有多个Handler,但是只有一个Looper。创建Handler之前,需要创建Looper,否则会报错。源码里面已经做了说明。

public Handler(Callback callback, boolean async) {

mLooper = Looper.myLooper();

if (mLooper == null) {//判断Looper是否被创建

throw new RuntimeException(

"Can’t create handler inside thread " + Thread.currentThread()

  • " that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = callback;

mAsynchronous = async;

}

再来看Looper的创建,是在prepare()方法里。

// sThreadLocal.get() will return null unless you’ve called prepare().

static final ThreadLocal sThreadLocal = new 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));

}

在创建之前去判断looper是否存在,存在就会抛出Only one Looper may be created per thread异常,这是在告诉我们一个线程只能有一个Looper。而TreadLocal的作用就是线程间隔离,确保一个线程对应一个Looper。还可以看看Looper构造方法的源码

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

MessageQueue的初始化是在Looper的构造方法里。不管一个线程有多少个Handler,相关联的都是同一个Looper和MessageQueue。

关于Handler,可以问的问题有很多,以上只是抽出一些我认为比较重要的问题。在寻找答案以后,我将Handler机制的整个过程在脑海中过了一遍,并且画了个草图。

Handler机制中重要类的相互关联图


Handler机制原理涉及几个重要的类:Handler、Message、MessageQueue、Looper。

就用子线程向主线程发送消息来说明整个过程。

首先在主线程创建一个Handler,在Handler类里面会创建Looper以及MessageQueue的对象,并且在Handler构造方法里面赋值

final Looper mLooper;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

目前已经更新的部分资料:



厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-FUeUhaZm-1711726429623)]

最后

目前已经更新的部分资料:

[外链图片转存中…(img-Ct02PMRE-1711726429623)]
[外链图片转存中…(img-umjbYdqs-1711726429623)]
[外链图片转存中…(img-LjgvylZz-1711726429624)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值