Handler 在整个 Android 开发体系中占据着很重要的地位,是一种标准的事件驱动模型,对开发者来说起到的作用很明确,就是为了实现线程切换或者是执行延时任务,稍微更高级一点的用法可能是为了保证多个任务在执行时的有序性。由于 Android 系统中的主线程有特殊地位,所以像 EventBus 和 Retrofit 这类并非 Android 独有的三方库,都是通过 Handler 来实现对 Android 系统的特殊平台支持。
该文章讲解了Handler的内部实现机制
该文章从问题出发来讲解了原理
三、几个问题的解答
1、更新UI的方式
2、子线程向主线程发消息,使主线程更新UI
3、主线程向子线程发消息
4、子线程向子线程发消息
5、Handler的实现中涉及到循环的地方?
6、Looper.loop阻塞主线程时,怎么响应用户操作和回调Activity生命周期相关的方法?
7、Handler内存泄漏?
1、更新UI的方式
共有四种方式(https://blog.csdn.net/ruancoder/article/details/52081614):
(1)Handler.sendEmptyMessage 或者 Handler.sendMessage
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_REFRESH) {
mTextView.setText("123");
}
}
};
private void refresh1() {
mHandler.sendEmptyMessage(MSG_REFRESH);
}
(2)Handler.post
private void refresh2() {
mHandler.post(new Runnable() {
@Override
public void run() {
mTextView.setText("123");
}
});
}
(3)View.post
private void refresh3() {
mTextView.post(new Runnable() {
@Override
public void run() {
mTextView.setText("123");
}
});
}
(4)runOnUiThread
private void refresh4() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText("blog.csdn.net/ruancoder");
}
});
}
在 Activity 的源码中:
...
final Handler mHandler = new Handler();
...
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
...
2、子线程向主线程发消息,使主线程更新UI
public class MainActivity extends AppCompatActivity {
TextView textView;
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(msg.what == 0x01){
//刷新UI操作
String ss = msg.obj.toString();
textView.setText(ss);
}
}
};
private void test(){
Thread thread = new Thread(){
@Override
public void run() {
super.run();
Message msg = Message.obtain();
msg.obj = "123";
msg.what = 0x01;
handler.sendMessage(msg);
}
};
thread.start();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_1);
test();
}
}
或者是在子线程中声明Handler,此时构造函数中需指明主线程的Looper:
ublic class MainActivity extends AppCompatActivity {
TextView textView;
private Handler handler;
private void test(){
Thread thread = new Thread(){
@Override
public void run() {
super.run();
handler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(msg.what == 0x01){
//刷新UI操作
String ss = msg.obj.toString();
textView.setText(ss);
}
}
};
Message msg = Message.obtain();
msg.obj = "123";
msg.what = 0x01;
handler.sendMessage(msg);
}
};
thread.start();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_1);
test();
}
}
3、主线程向子线程发消息
public class MainActivity extends AppCompatActivity {
Button button;
private Handler handler;
private void test(){
Thread thread = new Thread(){
@Override
public void run() {
super.run();
Looper.prepare();
handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.i("zxy","msg ::" + msg.obj.toString());
}
};
Looper.loop();
}
};
thread.start();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.btn);
test();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(handler != null){
Message msg = Message.obtain();
msg.obj = "123";
msg.what = 0x01;
handler.sendMessage(msg);
}else{
Toast.makeText(MainActivity.this, "请再点击一次", Toast.LENGTH_SHORT).show();
}
}
});
}
}
4、子线程向子线程发消息
同理,建立关于子线程A的aHandler,子线程B通过aHandler发消息给子线程A
或者通过全局变量
5、Handler的实现中涉及到循环的地方?
MessageQueue.enqueueMessage:从链表头向链表尾遍历,寻找链表中第一条时间戳比 msg 大的消息,将 msg 插到该消息的前面
MessageQueue.next:从MessageQueue中读取消息,如果消息队列中没有消息或者是队头消息还没到可以处理的时间,该方法就会调用nativePollOnce()将Loop线程休眠挂起
Looper.loop :循环向MessageQueue 取出消息并执行,当其中的MessageQueue.next() 方法触发阻塞操作时,loop()也会被阻塞着
6、Looper.loop阻塞主线程时,怎么响应用户操作和回调Activity生命周期相关的方法?
在application启动时,不止一个main线程,还有其它两个Binder线程(ApplicationThread和ActivityManagerProxy)用来和系统进程进行通信操作,接收系统进程发送的通知。
当系统收到因用户操作产生的通知时,会通过Binder方式跨进程通知ApplicationThread(?之后再看看);它通过Handler机制,往ActivityThread的MessageQueue中插入消息,唤醒主线程;loop()中queue.next()拿到消息,然后dispatchMessage完成事件分发。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bdi42lju-1670763529757)(C:\Users\zxy\AppData\Roaming\Typora\typora-user-images\image-20221211195500515.png)]
7、Handler内存泄漏?
在Java中,非静态内部类会持有一个外部类的隐式引用,可能会造成外部类无法被GC;
比如这里的Handler,就是非静态内部类,它会持有Activity的引用从而导致Activity无法正常释放。
而单单使用静态内部类,Handler就不能调用Activity里的非静态方法了,所以加上「弱引用」持有外部Activity。
private static class MyHandler extends Handler {
//创建一个弱引用持有外部类的对象
private final WeakReference<MainActivity> content;
private MyHandler(MainActivity content) {
this.content = new WeakReference<MainActivity>(content);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity= content.get();
if (activity != null) {
switch (msg.what) {
case 0: {
activity.notifyUI();
}
}
}
}
}
转换成Kotlin:(Tips:Kotlin 中的内部类,默认是静态内部类,使用inner修饰才为非静态~)
private class MyHandler(content: MainActivity) : Handler() {
//创建一个弱引用持有外部类的对象
private val content: WeakReference<MainActivity> = WeakReference(content)
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
val activity = content.get()
if (activity != null) {
when (msg.what) {
0 -> {
activity.notifyUI()
}
}
}
}
}