Handler面试那些事
2021/12/5 23:18:35
本文主要是介绍Handler面试那些事,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1、子线程到主线程通信都有哪些方式?子线程到主线程通信的原理?
这个是 Android 特有的概念。线程间的通信方式:eventbus、rxjava、livedata。然而,这些方式的底层原理都是基于 handler,所以,下面我将为大家讲解 handler 通信原理。
handler调度流程:
子线程: handler.sendMessage(msg) =》 handler.enqueueMessage =》MessageQueue.enqueueMessage()
主线程:Looper.loop=》queue.next()=》handler.handleMessage()
handler的核心原理图:
两个重要类的图解:
2、handler内存泄漏的原因是什么?
JVM 垃圾回收机制:GCroot 回收机制
持有链: static sThreadLocal -》 mLooper -》MessageQueue -》msg -》handler -》 activity
解决方法:打破持有链
3、子线程中如何创建handler?
- 写法一:直接在子线程创建 handler,错误
new Thread( () -> { Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(@NonNull Message msg) { return false; } }); mHandler.sendMessage(new Message()); } ).start();
报错展示:
Process: com.wust.empty02, PID: 25002 java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:207) at android.os.Handler.<init>(Handler.java:133) at com.wust.empty02.MainActivity.lambda$onCreate$0$MainActivity(MainActivity.java:20) at com.wust.empty02.MainActivity$$ExternalSyntheticLambda0.run(Unknown Source:2) at java.lang.Thread.run(Thread.java:919)
报错源码位置:
- 写法二:正确写法
new Thread( () -> { //创建该线程的 looper Looper.prepare(); //创建该线程的 handler Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(@NonNull Message msg) { return false; } }); //looper开启循环 Looper.loop(); } ).start();
这种写法有一个缺点:这样的话 该线程就只能创建一个handler。
- 写法三:通过 public Handler(@NonNull Looper looper) 该构造方法进行 handler 创建
package com.wust.empty02; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyHandlerThread t = new MyHandlerThread(); t.start(); try { //这句话如果去掉 就会导致 t.getmLooper() 为空,因为你无法保证 Handler handler = new Handler(t.getmLooper()); 在 t 线程 run 之后执行 Thread.sleep(1000*3); } catch (InterruptedException e) { e.printStackTrace(); } Handler handler = new Handler(t.getmLooper()); } } class MyHandlerThread extends Thread { private Looper mLooper; @Override public void run() { Looper.prepare(); this.mLooper = Looper.myLooper(); Looper.loop(); } public Looper getmLooper() { return mLooper; } }
从上面代码的注释 就可以很明显的看出其缺点之所在了。无法保证 t.getmLooper() 在 线程 run 方法之后执行。
- 方法四:使用 HandlerThread 创建线程
HandlerThread t = new HandlerThread("wustyq"); t.start(); Handler handler = new Handler(t.getLooper());
系统的这个 HandlerThread 中的 run 方法为什么就能保证在 t.getLooper() 之前执行呢??关键代码 + 关键思想如下:
为什么要用 synchronized ? 为了解决并发操作 =》 即 run 和 getLooper 只能同时执行一个。
为什么要用 notifyAll() ?因为有可能多个线程调用了wait()方法进行等待。
为什么要用 while?不用 if?因为这个 wait() 可能由别的线程 notify() 唤醒。所以要使用while反复检测。
4、子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?主线程呢?
quit:loop退出。防止内存泄漏。不会被停止。
5、handler如何处理发送延时消息?
会调用底层 Linux =》 epoll 完成等待
6、我们使用Message时应该如何创建它?
obtain()
这篇关于Handler面试那些事的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南