Handler
一、简介
Handler是用来结合线程的消息队列来发送、处理“Message对象”和“Runnable对象”的工具。每一个Handler实例之后会关联一个线程和该线程的消息队列。当你创建一个Handler的时候,从这时开始,它就会自动关联到所在的线程/消息队列,然后它就会陆续把Message/Runnalbe分发到消息队列,并在它们出队的时候处理掉。简单说,它是一套 Android 消息传递机制。
二、用途
延时操作。推送未来某个时间点将要执行的Message或者Runnable到消息队列;
线程之间的通讯。将消息推送到相应线程的消息队列中,等待处理。
三、使用方法
(1)sendMessage
// ************ 不配合线程使用 *************
// 获取一个Message对象,设置what为1
Message msg = Message.obtain();
msg.obj = data;
msg.what = IS_FINISH;
mHandler.sendMessage(msg);
// 接受并处理
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
tx.setText(msg.what + “”);
}
};
// ************ 配合线程使用 *************
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
Toast.makeText(MainActivity.this, “刷新UI、”, Toast.LENGTH_SHORT).show();
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
mHandler.sendEmptyMessage(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
常用 API:
boolean sendMessage (Message msg) : 发送消息。
boolean sendEmptyMessage (int what) : 直接拿到一个空的消息,并赋值what,然后发送到MessageQueue。
boolean sendMessageDelayed (Message msg, long delayMillis) : 在延迟delayMillis毫秒之后发送一个Message。
boolean sendMessageAtTime (Message msg, long uptimeMillis) : 在某个时间点执发送消息。
void removeMessages (int what) : 移除所有what值得Message对象。
(2)post
// ************ 不配合线程使用 *************
private Handler mHandler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
tvMessage.setText(“使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。”);
}
});
// ************ 配合线程使用 *************
new Thread(new Runnable() {
@Override
public void run() {
// 在子线程中实例化Handler同样是可以的,只要在构造函数的参数中传入主线程的Looper即可
Handler handler = new Handler(Looper.getMainLooper());
// 通过Handler的post Runnable到UI线程的MessageQueue中去即可
handler.post(new Runnable() {
@Override
public void run() {
// 在MessageQueue出队该Runnable时进行的操作
tvMessage.setText(“使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。”);
}
});
}
}).start();
常用 API:
boolean post (Runnable r) : 将Runnable对象加入MessageQueue。
boolean postAtTime (Runnable r, Object token, long uptimeMillis) : 在某个时间点执行Runnable r。
boolean postDelayed (Runnable r, long delayMillis) : 当前时间延迟delayMillis个毫秒后执行Runnable r。
void removeCallbacks (Runnable r, Object token) : 移除MessageQueue中的所有Runnable对象。
void removeCallbacksAndMessages (Object token) : 移除MessageQueue中的所有Runnable和Message对象。
四、原理
Handler 的初始化,其实是初始化 Looper 和 MessageQueue。通过 Looper.Prepare 实例化 Looper 和 MessageQueue ,并将 Looper 设置进 ThreadLocal(所以,使用 Handler 之前一定要调用 Looper.Prepare)。ThreadLocal.set 方法的作用是将设置的值(这里是当前初始化的 Looper)与当前线程进行绑定(当前线程就是调用 Looper.prepare 的线程)。主线程中没有显式的调用 Looper.Prepare 是因为,Android 系统已经帮我们调用了 Looper.Prepare。
Handler 在调用 sendMessage 的时候主要做了两件事:1.将自己设置给 Message 的 Target 变量,从而将 Handler 与 Message 绑定在一起;2.将 Message 放入 MessageQueue 队列中。
Looper.loop 从 MQ 中轮训获取消息,消息不为 Null 则回调 disPatchMessage 方法(Runnable 对象 OR handlerMessage)。
总结:
Handler : 负责发送和处理消息。
Message : 用来携带需要的数据。
MessageQueue : 消息队列,用来存储 Message 的。
Looper : 消息轮巡器,负责不停的从 MessageQueue 中取 Message。
子线程中使用 Handler:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
五、Handler 引发的内存泄漏
外部类Activity中定义了一个非静态内部类Handler,非静态内部类默认持有对外部类的引用。如果外部Activity突然关闭了,但是MessageQueue中的消息还没处理完,那么Handler就会一直持有对外部Activty的引用,垃圾回收器无法回收Activity,从而导致内存泄漏。
解决方法:1.停掉线程(切断了与 Activity 之间的关联)或移除 removexxx 消息;2.将Handler声明为静态类。改成静态内部类后,对外部类的引用设为弱引用,在垃圾回收时,会自动将弱引用的对象回收。如:
public class HandlerActivity extends AppCompatActivity {
private final MyHandler mHandler = new MyHandler(this);
private static final Runnable mRunnable = new Runnable() {
@Override
public void run() {
// 操作
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fourth);
mHandler.postDelayed(mRunnable, 1000*10);
finish();
}
private static class MyHandler extends Handler {
WeakReference<HandlerActivity> mWeakActivity;
public MyHandler(HandlerActivity activity) {
this.mWeakActivity = new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
final HandlerActivity mActivity = mWeakActivity.get();
if (mActivity != null) {
// 处理消息
}
}
}
}
六、HandlerThread
HandlerThread 是一种线程,它和普通的 Thread 之间的区别就是 HandlerThread 在创建的时候会提供自己该线程的 Looper 对象,不需要手动创建 Looper。
HandlerThread handlerThread = new HandlerThread(“downloadImage”); // 当前线程的名字,可以任意字符串
handlerThread.start(); // 必须先开启线程
/**
* 该callback运行于子线程
*/
class ChildCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message msg) {
// 在子线程中进行相应的网络请求
// 通知主线程去更新UI
mUIHandler.sendMessage(msg1);
return false;
}
}
Handler childHandler = new Handler(handlerThread.getLooper(),new ChildCallback());
final HandlerThread downloadAThread = new HandlerThread(“downloadAThread”);
downloadAThread.start();
Handler downloadAHandler = new Handler(downloadAThread.getLooper());
// downloadAHandler 子线程的 Handler
downloadAHandler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), “下载A完成”, Toast.LENGTH_SHORT).show();
mainHandler.post(new Runnable() {
@Override
public void run() {
tv_A.setText(“A任务已经下载完成”);
}
});
}
}, 1000 * 5);
当我们不需要HandlerThread的时候,我们可以调用quitSafely()或者quit()方法来结束这个线程。
参考文章:Android基础夯实–你了解Handler有多少?,Android面试常客之Handler全解
发表回复