一. 前言
1. 什么是Handler?
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue。
简单地说,就是一套 Android 传递机制。
2. 如何使用 Handler?
① 创建Message - obtainMessage
② 发送Message - sendMessage,post
③ 处理Message - handleMessage
3. Message
① 两个整型值,arg1,arg2,轻量级存储int类型的数据
② 一个Object值,任意对象
③ replyTo,线程通信的时候使用
④ what,用户自定义的消息码让接受者识别消息
二. Handler 的 工作原理
Android Handler:图文解析 Handler通信机制 的工作原理
三. Handler的使用方式
Android:这是一份Handler消息传递机制 的使用教程
四. Handler源码分析
Android:这是一份Handler消息传递机制 的使用教程
五. Handler的内存泄漏
Android 内存泄露:详解 Handler 内存泄露的原因
六. 实际例子
1. 常用的方法
1 2
| public final boolean sendEmptyMessage(int what)
|
1 2
| public final boolean sendMessage(@NonNull Message msg)
|
1 2
| public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis)
|
1 2
| public final boolean post(@NonNull Runnable r)
|
1 2
| public final boolean postDelayed(@NonNull Runnable r, long delayMillis)
|
2. 实战例子
① 没有解决内存泄漏的版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class MainActivity extends AppCompatActivity {
private static final int MESSAGE_CODE = 1000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); @SuppressLint("HandlerLeak") final Handler handler = new Handler(){ @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); switch (msg.what){ case MESSAGE_CODE: Toast.makeText(MainActivity.this, (String) msg.obj, Toast.LENGTH_SHORT).show(); break; } } }; findViewById(R.id.send).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message message = handler.obtainMessage(); message.arg1 = 1; message.arg2 = 2; message.obj = "message"; message.what = MESSAGE_CODE; handler.sendMessage(message); } }); } }
|

② 解决内存泄漏的版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| public class MainActivity extends AppCompatActivity {
private static final int MESSAGE_CODE = 1000;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
final Handler handler = new MyHandler(this);
findViewById(R.id.send).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message message = handler.obtainMessage(); message.arg1 = 1; message.arg2 = 2; message.obj = "message"; message.what = MESSAGE_CODE; handler.sendMessage(message);
} }); }
private static class MyHandler extends Handler{
private WeakReference<Activity> reference;
public MyHandler(Activity activity) { this.reference = new WeakReference<>(activity); }
@Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg);
switch (msg.what){ case MESSAGE_CODE: Activity main = reference.get(); Toast.makeText(main, (String) msg.obj, Toast.LENGTH_SHORT).show(); break; } } } }
|
1> 原因:
在Handler
消息队列 还有未处理的消息 / 正在处理消息时,消息队列中的Message
持有Handler
实例的引用
由于Handler
= 非静态内部类 / 匿名内部类(2种使用方式),故又默认持有外部类的引用(即MainActivity
实例)
上述的引用关系会一直保持,直到Handler
消息队列中的所有消息被处理完毕
在Handler
消息队列 还有未处理的消息 / 正在处理消息时,此时若需销毁外部类MainActivity
,但由于上述引用关系,垃圾回收器(GC)
无法回收MainActivity
,从而造成内存泄漏。
2> 解决方案:
从上面可看出,造成内存泄露的原因有2个关键条件:
- 存在“未被处理 / 正处理的消息 ->
Handler
实例 -> 外部类” 的引用关系
Handler
的生命周期 > 外部类的生命周期
即 Handler
消息队列 还有未处理的消息 / 正在处理消息 而 外部类需销毁。
方式一:静态内部类+弱引用
静态内部类 不默认持有外部类的引用,从而使得 “未被处理 / 正处理的消息 -> Handler
实例 -> 外部类” 的引用关系 的引用关系 不复存在。
使用WeakReference弱引用持有Activity实例,弱引用的对象拥有短暂的生命周期。在垃圾回收器线程扫描时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
方式二:当外部类结束生命周期时,清空Handler内消息队列
不仅使得 “未被处理 / 正处理的消息 -> Handler
实例 -> 外部类” 的引用关系 不复存在,同时 使得 Handler
的生命周期(即 消息存在的时期) 与 外部类的生命周期 同步。
1 2 3 4 5 6
| @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); }
|
为了保证Handler
中消息队列中的所有消息都能被执行,此处推荐使用解决方案1解决内存泄露问题,即 静态内部类 + 弱引用的方式。
③ 源码
Handler