type
status
date
slug
summary
tags
category
password
icon
Android 的 Handler 机制
- 本质:在某个指定的运⾏中的线程上执⾏代码
- 思路:在接受任务的线程上执⾏循环判断
- 基本实现:
- Thread ⾥ while 循环检查
- 加上 Looper(优势在于⾃定义 Thread 的代码可以少写很多):
- 再加上 Handler(优势在于功能分拆,⽽且可以有多个 Handler)
- Java 的 Handler 机制:
- HandlerThread:具体的线程
- Looper:负责循环、条件判断和任务执⾏
- 在 loop 方法中会
- Handler:负责任务的定制和线程间传递
- Handler 构造方法中需要一个 Looper 成员变量
- Handler 也能够接受 Message(会把 Handler 封装进 Message 中)转发给 Looper
- Message:负责封装消息特征
- 内部的 target 成员变量是一个 Handler,会在 Looper 的 loop 方法中被调用
dispatchMessage()
Android 中,通过 Looper 类中的 ThreadLocal 变量存储 Looper,每个线程在 run() 方法中先通过 
Looper.prepare()
方法创建一个自己的 Looper(Main 线程是通过 Looper.prepareMainLooper()
),存储在 Looper 的 ThreadLocal 变量中,这样每个线程调用 ThreadLocal 变量获取到的都是自己的 Looper。而Looper 中存储了消息队列 MessageQueue,通过 Looper.loop() 方法去死循环遍历消息队列中的消息,并调用每个 Message 自己 Handler 的 dispatchMessage()
方法去执行消息
- AsyncTask:
- AsyncTask 的内存泄露
- 众所周知的原因:AsyncTask 持有外部 Activity 的引⽤
- 没提到的原因:执⾏中的线程不会被系统回收
- Java 回收策略:没有被 GC Root 直接或间接持有引⽤的对象,会被回收 GC Root:
- 运⾏中的线程
- 静态对象
- 来⾃ native code 中的引⽤
- 所以:
- AsyncTask 的内存泄露,其他类型的线程⽅案(Thread、Executor、HandlerThread)⼀样都有,所以不要忽略它们,或者认为 AsyncTask ⽐别的⽅案更危险。并没有。
- 就算是使⽤ AsyncTask,只要任务的时间不⻓(例如 10秒 之内),那就完全没必要做防⽌内存泄露的处理。
Service 和 IntentService
- Service:后台任务的活动空间,并不会自动把内容放在后台线程,需要自己开线程切换到后台。适⽤场景:⾳乐播放器等
- IntentService:将单个任务放在后台执行后⾃动关闭的 Service
Executor、AsyncTask、HandlerThead、IntentService 的选择
原则:哪个简单⽤哪个
- 能⽤ Executor 就⽤ Executor
- 需要⽤到「后台线程推送任务到 UI 线程」时,再考虑 AsyncTask 或者 Handler
- HandlerThread 的使⽤场景:原本它设计的使⽤场景是「在已经运⾏的指定线程上执⾏代码」,但现实开发中,除了主线程之外,⼏乎没有这种需求,因为 HandlerThread 和 Executor 相⽐在实际应⽤中并没什么优势,反⽽⽤起来会麻烦⼀点。不过,这⼆者喜欢⽤谁就⽤谁吧。
- IntentService:⾸先,它是⼀个 Service;另外,它在处理线程本身,没有⽐ Executor 有任何优势
关于 Executor 和 HandlerThread 的关闭
如果在界⾯组件⾥创建 Executor 或者 HandlerThread,记得要在关闭的时候(例如 Activity.onDestroy() )关闭 Executor 和 HandlerThread。
- 作者:shuouyang
- 链接:https://notion-tree.vercel.app/article/faa71b76-30dc-4b1b-a306-62205df84b42
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。