Android消息机制1-Handler(Java层)

75 阅读3分钟

Android 的消息机制可以用一个​​邮局系统​​来比喻,帮助你理解各个组件如何协同工作。我们用四个核心角色来解释:​​Handler(快递员)​​、​​Looper(邮局分拣员)​​、​​MessageQueue(邮局信箱)​​、​​Message(信件)​​。


一、核心角色分工

  1. ​Message(信件)​

    • 包含消息内容(比如文字、任务指令)。
    • 信件可以被重复使用(节省资源,类似回收旧信封)。
  2. ​MessageQueue(信箱)​

    • 存放所有待处理的信件,按接收时间排序。
    • 如果信箱空了,会暂时“休眠”等待新信件。
  3. ​Looper(分拣员)​

    • 不断检查信箱,取出下一封该处理的信件。
    • 一个线程只有一个分拣员(比如主线程自带分拣员)。
  4. ​Handler(快递员)​

    • 负责​​送信​​(发送消息到信箱)。
    • 负责​​处理信​​(收到分拣员送来的信后执行任务)。

二、工作流程(以子线程更新UI为例)

  1. ​创建邮局(Looper)​
    子线程默认没有分拣员,需要手动开邮局:

    java
    Copy
    Looper.prepare(); // 创建分拣员和信箱
    Handler handler = new Handler(); // 绑定当前分拣员
    Looper.loop(); // 分拣员开始工作(死循环取信)
    
  2. ​发送信件(Handler发消息)​
    子线程做完耗时任务后,通过Handler送信到主线程的信箱:

    java
    Copy
    handler.post(() -> {
        // 这封信的内容是更新UI(会在主线程执行)
        textView.setText("任务完成");
    });
    
  3. ​处理信件(Looper分拣)​

    • 主线程的Looper一直检查自己的信箱,发现新信件后交给对应的Handler。
    • Handler根据信件内容执行任务(比如更新UI)。

三、关键细节

  1. ​消息优先级​

    • ​即时信件​​:通过 post() 或 sendMessage() 直接发送,按时间顺序处理。
    • ​加急信件​​:标记为异步消息(如UI绘制),可插队处理(需搭配同步屏障)。
  2. ​避免内存泄漏​

    • 如果Handler是Activity的内部类,会导致Activity无法销毁。
      ​解决​​:用静态内部类 + 弱引用。
  3. ​复用Message​

    • 不要一直 new Message(),用 Message.obtain() 从回收池取旧信件,节省资源。
  4. ​线程切换​

    • Handler能跨线程因:信箱归属某个线程的Looper,但其他线程可以投递消息到它。

四、常见问题

  • ​为什么主线程不用手动创建Looper?​
    Android在启动主线程时自动调用了 Looper.prepareMainLooper()
  • ​主线程Looper会卡死吗?​
    不会。虽然Looper是死循环,但有新消息时才唤醒,没消息时休眠(类似“待机”)。
  • ​子线程Toast报错?​
    Toast内部依赖Handler,子线程没有Looper导致崩溃。需先调用 Looper.prepare()

总结

​消息机制的本质是“事件驱动”​​: