关于Handler,看看面试官都问了我哪些?这些你都知道吗

本文详细解答了Android开发中Handler的基础概念,包括线程、Looper和MessageQueue的关系,Handler内存泄漏的原因及解决方案,以及如何在主线程和子线程中正确使用Handler。还提供了处理子线程Looper空闲时的策略和防止内存泄漏的最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做 Android 开发肯定离不开跟 Handler 打交道,它通常被我们用来做主线程与子线程之间的通信工具,而 Handler 作为 Android 中消息机制的重要一员也确实给我们的开发带来了极大的便利。
可以说只要有异步线程与主线程通信的地方就一定会有 Handler。

在面试中Handler也是经常被问的一个点,那么本篇文章就以问答的方式,带你了解一下关于Handler的重要知识点。

面试官:一个线程有几个 Looper?几个 Handler?

小王:
一个Thread只能有一个Looper,一个MessageQueen,可以有多个Handler
以一个线程为基准,他们的数量级关系是: Thread(1) : Looper(1) : MessageQueue(1) : Handler(N)

面试官:Handler 内存泄漏原因? 以及最佳解决方案?
小王:

  • 泄露原因:
    Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露。 这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露。

  • 解决方案

  1. 最直接的思路就是避免使用非静态内部类。使用Handler的时候,放在一个新建的文件中来继承Handler或者使用静态的内部类来替代。静态内部类不会隐含的持有外部类的引用,因此这个activity也就不会出现内存泄漏问题。
  2. 如果你需要在Handler内部调用外部Activity的方法,你可以让这个Handler持有这个Activity的弱引用,这样便不会出现内存泄漏的问题了。
  3. 另外,对于匿名类Runnable,我们同样可以设置成静态的,因为静态内部类不会持有外部类的引用。
  4. 注意:如果使用Handler发送循环消息,最好是在Activity的OnDestroy方法中调用**mLeakHandler.removeCallbacksAndMessages(null);**移除消息。(这不是解决内存泄漏的方法)

5.两种解决办法如下:

弱引用(WeakReference)

public class SampleActivity extends Activity {

/**

  • Instances of static inner classes do not hold an implicit
  • reference to their outer class.
  • 弱引用的方式
    */
    private static class MyHandler extends Handler {
    private final WeakReference mActivity;
    public MyHandler(SampleActivity activity) {
    mActivity = new WeakReference(activity);
    }

@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
//to Something
}
}
}

静态

//定义成static的,因为静态内部类不会持有外部类的引用
private final MyHandler mHandler = new MyHandler(this);
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() {//to something}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
finish();
}
}

面试官:为何主线程可以new Handler?如果想要在子线程中new Handler 要做些什么准备?
小王:
每一个handler必须要对应一个looper,主线程会自动创建Looper对象,不需要我们手动创建,所以主线程可以直接创建handler。
在new handler的时候没有传入指定的looper就会默认绑定当前创建handler的线程的looper,如果没有looper就报错。

因为在主线程中,Activity内部包含一个Looper对象,它会自动管理Looper,处理子线程中发送过来的消息。而对于子线程而言,没有任何对象帮助我们维护Looper对象,所以需要我们自己手动维护。
所以要在子线程开启Handler要先创建Looper,并开启Looper循环

如果在子线程中创建了一个Handler,那么就必须做三个操作:

  1. prepare();
  2. loop();
  3. quit();

面试官:子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
小王:
在Handler机制里面有一个Looper,在Looper机制里面有一个函数,叫做quitSafely()和quit()函数,这两个函数是调用的MessageQueue的quit()。

/**

  • Quits the looper.
  • Causes the {@link #loop} method to terminate without processing any
  • more messages in the message queue.
  • Any attempt to post messages to the queue after the looper is asked to quit will fail.
  • For example, the {@link Handler#sendMessage(Message)} method will return false.
  • Using this method may be unsafe because some messages may not be delivered
  • before the looper terminates. Consider using {@link #quitSafely} instead to ensure
  • that all pending work is completed in an orderly manner.
  • @see #quitSafely
    */
    public void quit() {
    mQueue.quit(false);
    }

/**

  • Quits the looper safely.
  • Causes the {@link #loop} method to terminate as soon as all remaining messages
  • in the message queue that are already due to be delivered have been handled.
  • However pending delayed messages with due times in the future will not be
  • delivered before the loop terminates.
  • Any attempt to post messages to the queue after the looper is asked to quit will fail.
  • For example, the {@link Handler#sendMessage(Message)} method will return false.

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

再进入到MessageQueue的quit()函数。

void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException(“Main thread not allowed to quit.”);

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

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

总结

**其实上面说了这么多,钱是永远赚不完的,在这个知识付费的时代,知识技能提升才是是根本!我作为一名8年的高级工程师,知识技能已经学习的差不多。**在看这篇文章的可能有刚刚入门,刚刚开始工作,或者大佬级人物。

像刚刚开始学Android开发小白想要快速提升自己,最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以这里分享一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

这么重要的事情说三遍啦!点赞+点赞+点赞 免费分享所有学习秘籍!
直达领取链接:点击链接免费领取【Android高级架构师

【Android高级架构师系统学习资料】高级架构师进阶必备——设计思想解读开源框架

第一章、热修复设计
第二章、插件化框架设计
第三章、组件化框架设计
第四章、图片加载框架
第五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack

架构师系统学习资料】高级架构师进阶必备——设计思想解读开源框架

第一章、热修复设计
第二章、插件化框架设计
第三章、组件化框架设计
第四章、图片加载框架
第五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值