零零碎碎的东西老是记不长久,仅仅学习别人的文章也只是他人咀嚼后留下的残渣。无心中发现了这个每日一道面试题,想了想若是只是简单地去思考,那么不只会收效甚微,甚至难一点的题目本身可能都懒得去想,坚持不下来。因此不如把每一次的思考、理解以及别人的看法记录下来。不只加深本身的理解,更要激励本身坚持下去。java
SDK文档是这么说的。git
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.github
咱们通常就是用来更新UI线程的。具体点就是在子线程进行耗时操做,好比获取网络图片,而后须要在主线程更新图片,就须要handler+Message+Loop+MessageQueue来帮忙啦。面试
可是若是你直接建立一个handler对象,而后重写内部handlerMessage方法,那么AS必定会提醒你会有内存泄漏的可能。网络
Android内存泄漏:须要被GC回收的对象由于被其余存活的对象所持有引用,而致使GC不能回收此对象。那么这块内存就会在程序运行期间长期被占据,形成系统内存的浪费,使系统运行缓慢甚至崩溃。ide
那么handler何时会形成内存泄漏呢?oop
发送延迟消息学习
众所周知,匿名内部类持有外部类的引用,那么handler对象就会持有activity对象的引用。handler发送message到MessageQueue,message持有handler的引用,而MessageQueue会持有message的引用,而MessageQueue是属于TLS(ThreadLocalStorage)线程,是与Activity不一样的生命周期。spa
因此当Activity的生命周期结束后,而MessageQueue中还存在未处理的消息,那么上面一连串的引用关系就不容许Activity的对象被回收,就形成了内存泄漏。线程
知道了内存泄漏是由引用链形成的,那么解决方法也就是破坏上面的引用链。
首先是引用的类型,有强引用、软引用、弱引用、虚引用,上面的引用链都是强引用。
因此第一种方法,自定义静态内部类,若是想使用外部类的方法,那就经过弱引用的方法引入Activity对象。
public class BaseActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void myHandleMessage(Message msg){}
static class MyHandler extends Handler{
WeakReference<BaseActivity> mActivityReference;
public MyHandler(BaseActivity activity){
mActivityReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
BaseActivity activity = mActivityReference.get();
if(activity != null){
activity.myHandleMessage(msg);
}
}
}
}
复制代码
你能够自定义在BaseActivity中,在其余Activity中建立Myahndler对象,经过重写myHandleMessage方法进行消息处理。
这种方法就是处理了Activity与Handler之间的引用,这种引用能够再GC时被回收。
第二种,就是处理后面的引用。既然是Activity要被回收时还有未被处理的消息,那么在Activity要被回收时清除消息就能够了。
@Override
protected void onDestroy() {
super.onDestroy();
if(mHandler != null){
mHandler.removeCallbacksAndMessages(null);
}
}
复制代码