提到handler,大家都想到些什么呢,切换线程?延时操作实现定时器?
这次我们说下Android最常见的Handler,相关知识也是面试必考
先说下基本的用法和工作流程
用法很简单,定义一个handler,重写handleMessage方法处理消息,用send方法通知handler
但是主线程和其他线程用法却有点不一样!其实下面线程里面的用法才是完整的,
Looper.prepare()方法其实是创建looper,并且绑定到该线程
然后定义handler
Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
handler.sendEmptyMessage(0);
handler.sendEmptyMessageDelayed(0, 1000);
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}).start();
在新线程中是handler的完成流程。loop(),该方法意思就是这个looper会不断从MessageQueue中获取message并且发送给对应的hander
looper相当于一个工具人,handler说要发送消息啦,工具人就把消息放到消息队列里面进行管理
同时他会不停的loop,从消息队列里面拿出队头消息给到当初的那个对应的handler,
然后handler通过handlemessage进行处理
所以呢,handler内部其实就是三部分
- looper,关联线程并且负责从消息队列拿出消息分发给handler
- messageQueue,消息队列,负责消息存储管理
- handler,负责发送和处理消息
原理就这么多,下面说几个重要的知识点
知识点,面试点
知识点一:主线程的looper呢??
看下源码,这里需要涉及到的一个类android.app.ActivityThread,这个类中的main方法是整个app的最开始执行的方法,是app的入口,看下main方法源码
Looper.prepareMainLooper();
// ***
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
Looper.prepareMainLooper();
Looper.loop();
其中最重要的就是这两句,调用了prepareMainLooper创建了主线程的looper,然后调用loop方法开始***死循环***
ok,loop方法是找到了。那loop为什么可以一直取消息呢?一直工作?看看源码
//Looper
public static void loop() {
//...
for (; ; ) {
// 不断从 MessageQueue 获取 消息
Message msg = queue.next();
//退出 Looper
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//...
}
}
找到原因了。其实就是一个死循环,所以loop方法可以一直执行工具人的工作
知识点2:为什么死循环都可以被写出来啊?不会oom吗??
说白了,其实死循环也是有意为之,线程在可执行代码执行完后,就会终止,而主线程肯定需要一直运行,所以死循环就能保证这一点。
而activity的生命周期是怎么实现在死循环体外正常执行的呢?
答:其实就是通过这个handler的,比如onPause方法,当主线程Looper在loop的时候,收到暂停的消息时,就会把消息分发给主线程的handleMessage处理,然后最后会调用到activity的onPause方法
建议去知乎看一下这个答案,说的很详细
知识点3:内存泄漏??
首先为什么会发送内存泄漏?
handler作为内部类会持有外部类的引用,当发送延迟消息时,就有可能发生处理消息的时候,activity已经销毁了,从而导致内存泄漏
怎么解决?
答:定义静态内部类,并且在ondestory里面移除所有消息
直接移除不就行了?还需要静态内部类?
答:ondestory不一定执行的嘛
其实所有的内部类内存泄漏都是一样的处理方法,内部类持有外部类引用相关内容可以看我在java内容系列里面的内部类文章
上代码
private static class MemoryLeakSafeHandler extends Handler {
private WeakReference<HandlerInfoActivity> ref;
public MemoryLeakSafeHandler(HandlerInfoActivity activity) {
this.ref = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerInfoActivity activity = ref.get();
if (activity != null) {
activity.handleMessage(msg);
}
}
}
MemoryLeakSafeHandler handler;
public void handleMessage(Message msg) {
}
@Override
protected void onDestroy() {
handler.removeCallbacksAndMessages(null);
super.onDestroy();
}