- Handler 是什么?
- 为什么需要 Handler?
- Handler 如何使用?
- handler 存在的问题及改进?
Handler:是一个消息分发对象,进行发送和处理消息,并且其 Runnable 对象与一个线程的 MessageQueue 关联。
作用:调度消息,将一个任务切换到某个指定的线程中去执行。
为什么需要 Handler?
子线程不允许访问 UI
假若子线程允许访问 UI,则在多线程并发访问情况下,会使得 UI 控件处于不可预期的状态。
传统解决办法:加锁,但会使得UI访问逻辑变的复杂,其次降低 UI 访问的效率。
引入 Handler
采用单线程模型处理 UI 操作,通过 Handler 切换到 UI 线程,解决子线程中无法访问 UI 的问题。
Handler 使用
方式一: post(Runnable)
- 创建一个工作线程,实现 Runnable 接口,实现 run 方法,处理耗时操作
创建一个 handler,通过 handler.post/postDelay,投递创建的 Runnable,在 run 方法中进行更新 UI 操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16new Thread(new Runnable() {
public void run() {
/**
* 耗时操作
*/
handler.post(new Runnable() {
public void run() {
/**
* 更新UI
*/
}
});
}
}).start();
方式二: sendMessage(Message)
- 创建一个工作线程,继承 Thread,重新 run 方法,处理耗时操作
- 创建一个 Message 对象,设置 what 标志及数据
- 通过 sendMessage 进行投递消息
创建一个handler,重写 handleMessage 方法,根据 msg.what 信息判断,接收对应的信息,再在这里更新 UI。
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
30private Handler handler = new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) { //判断标志位
case 1:
/**
* 获取数据,更新UI
*/
break;
}
}
};
public class WorkThread extends Thread {
public void run() {
super.run();
/**
* 耗时操作
*/
Message msg =Message.obtain(); //从全局池中返回一个message实例,避免多次创建message(如new Message)
msg.obj = data;
msg.what=1; //标志消息的标志
handler.sendMessage(msg);
}
new WorkThread().start();
Handler 存在的问题
###内存方面
Handler 被作为 Activity 引用,如果为非静态内部类,则会引用外部类对象。当 Activity finish 时,Handler可能并未执行完,从而引起 Activity 的内存泄漏。故而在所有调用 Handler 的地方,都用静态内部类。
异常方面
当 Activity finish 时,在 onDestroy 方法中释放了一些资源。此时 Handler 执行到 handlerMessage 方法,但相关资源已经被释放,从而引起空指针的异常。
避免
- 如果是使用 handlerMessage,则在方法中加try catch。
- 如果是用 post 方法,则在Runnable方法中加try catch。
Handler 的改进
- 内存方面:使用静态内部类创建 handler 对象,且对 Activity 持有弱引用
- 异常方面:不加 try catch,而是在 onDestory 中把消息队列 MessageQueue 中的消息给 remove 掉。
则使用如下方式创建 handler 对象:
1 | /** |
并在 onDesotry 中销毁:
1 |
|
Handler 的使用实现
- 耗时操作采用从网络加载一张图片
- 继承 Thread 或实现 Runnable 接口的线程,与 UI 线程进行分离,其中 Runnable 与主线程通过回调接口进行通信,降低耦合,提高代码复用性。
在 Activity 中创建 handler 对象,调用工作线程执行
1 | public class MainActivity extends AppCompatActivity { |
1 | /** |
方式一:实现 runnable 接口,通过 post(Runnable)通信,并通过给定的回调接口通知 Activity 更新
1 | public class PostRunnable implements Runnable { |
方式二:继承Thread,通过handler的sendMessage通信
1 | public class SendThread extends Thread { |