安卓面试之Handler

打印 上一主题 下一主题

主题 1878|帖子 1878|积分 5634

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
目录 
1.Handler 的原理

2.Handler核心组件包括

3.Handler的工作流程:

4.一个线程有几个looper,几个消息队列,几个消息

5.延迟消息的实现

6.Handler 为什么会持有 Activity 的引用?

7.Handler 在什么环境下会造成内存泄漏?

8.使用静态内部类创建 Handler,如何实行 Activity 的方法?

9.在主线程和子线程中创建Handler的区别?

10.Looper的创建机会



1.Handler 的原理

Handler 是 Android 中用于线程间通讯的核心机制,尤其用于子线程向主线程发送消息更新 UI。

2.Handler核心组件包括

①Loope: 负责循环从消息队列(MessageQueue)中取出消息,并分发给对应的 Handler 处理。每个线程只能有一个 Looper。
②MessageQueue:一个按实行时间排序的优先级队列,存储待处理的 Message。
③Handler:用于发送消息到 MessageQueue,并处理 Looper 分发的消息。

3.Handler的工作流程:

①Handler 发送消息(如 sendMessage() 或 post(Runnable) ),消息会被插入到关联的 MessageQueue 中。
② Looper 不停循环,从 MessageQueue 中取出符合实行时间的消息。
③消息(的 target字段即发送它的 Handler)会调用 handleMessage() 处理消息。

4.一个线程有几个looper,几个消息队列,几个消息

1 个线程 = 1 个 Looper + 1 个 MessageQueue,可创建多个 Handler。
①每个线程最多一个 Looper,通过 Looper.prepare() 初始化,若重复调用会抛出非常。
②每个 Looper 对应一个 MessageQueue,只能有一个消息队列
③一个线程可以有多个Handler,所有的handler共享同一个Looper和MessageQueue

5.延迟消息的实现

延迟消息是通过 postDelayed() 或 sendMessageDelayed() 发送。
实现原理:
①消息的 `when` 字段被设置为当前时间 + 延迟时间(绝对时间戳)。
②MessageQueue 内部按 `when` 排序,保证最早到期的消息先被处理。
③Looper 取出消息时,会检查当前时间是否到了消息的实行时间,若未到 `when`,则盘算等待时间,进入休眠(通过 `epoll_wait`),制止 CPU 占用。新消息插入时可能唤醒队列。

6.Handler 为什么会持有 Activity 的引用?

①非静态内部类的隐式引用:当 Handler 定义为 Activity 的非静态内部类时,会隐式持有外部类(Activity)的引用。这是 Java 的内部类机制决定的。
②消息队列的引用:Handler 发送的 Message 会持有 Handler 的引用,而消息可能被主线程的 Looper 消息队列(MessageQueue)长时间持有(如延迟消息)。此时,若 Activity 被销毁,但消息未处理完毕,Handler 会制止 Activity 被回收。

7.Handler 在什么环境下会造成内存泄漏?

延迟消息未处理:当 Handler 发送了延迟消息(如 `postDelayed()`)且消息未处理前,Activity 被销毁,但消息仍持有 Handler 的引用,导致 Activity 无法被 GC 回收。

8.使用静态内部类创建 Handler,如何实行 Activity 的方法?

解决方案:弱引用 + 生命周期管理
①静态内部类:将 Handler 定义为静态内部类,制止隐式持有 Activity 的引用。
②弱引用 Activity:通过 `WeakReference` 持有 Activity 的引用,制止强引用导致内存泄漏。
③安全调用:在 `handleMessage()` 中检查 Activity 是否存活,再调用其方法。
  1. ```java
  2. public class MyActivity extends Activity {
  3.     private MyHandler mHandler;
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.         mHandler = new MyHandler(this);
  8.     }
  9.     // 静态内部类 + 弱引用
  10.     private static class MyHandler extends Handler {
  11.         private final WeakReference<MyActivity> mActivityRef;
  12.         MyHandler(MyActivity activity) {
  13.             mActivityRef = new WeakReference<>(activity);
  14.         }
  15.         @Override
  16.         public void handleMessage(Message msg) {
  17.             MyActivity activity = mActivityRef.get();
  18.             if (activity == null || activity.isDestroyed()) return; // 检查 Activity 是否有效
  19.             activity.doSomething(); // 调用 Activity 的方法
  20.         }
  21.     }
  22.     @Override
  23.     protected void onDestroy() {
  24.         super.onDestroy();
  25.         // 移除所有消息,避免无效操作
  26.         mHandler.removeCallbacksAndMessages(null);
  27.     }
  28. }
  29. ```
复制代码


9.在主线程和子线程中创建Handler的区别?

选择依据:根据使命是否必要更新UI(主线程)或是否耗时(子线程),决定在哪个线程创建 Handler。

①在主线程中创建 Handler:

主线程创建 Handler:主线程默认已经初始化了 `Looper`,因此可以直接创建 `Handler`绑定到主线程的 Looper,用于更新UI或处理主线程使命。

  1. ```java
  2.   // 在主线程中创建 Handler
  3.   Handler handler = new Handler(Looper.getMainLooper()) {
  4.       @Override
  5.       public void handleMessage(Message msg) {
  6.           // 在主线程中处理消息
  7.           switch (msg.what) {
  8.               case 1:
  9.                   // 更新UI
  10.                   break;
  11.           }
  12.       }
  13.   };
  14.   // 在子线程中发送消息
  15.   new Thread(() -> {
  16.       Message message = handler.obtainMessage(1);
  17.       handler.sendMessage(message);
  18.   }).start();
  19.   ```
复制代码
②在子线程中创建 `Handler:

子线程创建 Handler:子线程默认没有初始化 `Looper`,因此必要手动调用 `Looper.prepare()` Looper.loop()`。绑定到子线程的 Looper,用于实行耗时使命或实现使命队列。

  1.   ```java
  2.   // 在子线程中创建 Handler
  3.   new Thread(() -> {
  4.       Looper.prepare(); // 初始化 Looper
  5.       Handler handler = new Handler() {
  6.           @Override
  7.           public void handleMessage(Message msg) {
  8.               // 在子线程中处理消息
  9.               switch (msg.what) {
  10.                   case 1:
  11.                       // 执行耗时任务
  12.                       break;
  13.               }
  14.           }
  15.       };
  16.       Looper.loop(); // 启动消息循环
  17.   }).start();
  18.   ```
复制代码


10.Looper的创建机会

①主线程的 Looper 是应用启动时主动创建的(由 `ActivityThread` 的 `main()` 方法主动创建)。

主线程的 Looper 会一直运行,直到应用退出。

  1.   ```java
  2.   public static void main(String[] args) {
  3.       // 初始化主线程的 Looper
  4.       Looper.prepareMainLooper();
  5.       // 创建 ActivityThread 对象
  6.       ActivityThread thread = new ActivityThread();
  7.       thread.attach(false);
  8.       // 启动消息循环
  9.       Looper.loop();
  10.   }
  11.   ```
复制代码
②子线程的 Looper必要手动调用 Looper.prepare() 和 Looper.loop() 来创建和启动。

可以通过 `Looper.quit()` 退出消息循环。

  1.   ```java
  2.   new Thread(() -> {
  3.       // 初始化 Looper
  4.       Looper.prepare();
  5.       // 创建 Handler
  6.       Handler handler = new Handler() {
  7.           @Override
  8.           public void handleMessage(Message msg) {
  9.               // 处理消息
  10.           }
  11.       };
  12.       // 启动消息循环
  13.       Looper.loop();
  14.   }).start();
  15.   ```
复制代码
③Activity` 中的 `Looper:

Activity` 默认使用主线程的 Looper`,无需手动初始化。

如果必要在子线程中使用 `Handler`,必须手动创建 `Looper`。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

老婆出轨

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表