去除烦人的This Handler class should be static or leaks might occur

现象

这个Wraning已经出现很久了,一直都没怎么关心,今天为了治疗我的强迫症,决心要消灭项目中所有的Warning,这个Warning是我觉得很鸡肋的一个,特撰此文记录。
如果直接写一个Handler的匿名类或者子类,就会出现”This Handler class should be static or leaks might occur”的Warning,这是为什么呢?如果不写成静态的Handler就会内存泄露,蒙谁呢。

解决

这个Warning的详细描述是这样的:


Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.


说把Handler声明成静态的,在外部类中用弱引用包装外部类的实例,在Handler初始化的时候传进来,这样我们就可以在这个Handler中使用外部类的成员变量啦,巴拉巴拉…一大堆,照做就是了,大概是这个样子:

private static final class PagerHandler extends Handler {
    WeakReference mMainActivityWeakReference;

    public PagerHandler(MainActivity mainActivity) {
        mMainActivityWeakReference = new WeakReference<>(mainActivity);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        MainActivity mainActivity = mMainActivityWeakReference.get();
        int childCount = mainActivity.mPagerAdapter.getCount();
        int nextItem = mainActivity.mViewPager.getCurrentItem() + 1;
        if (nextItem == childCount) {
            nextItem = 0;
        }
        mainActivity.mViewPager.setCurrentItem(nextItem,true);
        mainActivity.mPagerHandler.sendEmptyMessageDelayed(PAGER_TICK,3000);
    }
}

我比较偷懒,在Handler内部包装的弱引用,人家上边要求的是在外部类中包装自身的弱引用直接传入到Handler的构造,其实都可以达到一样效果的。这个无所谓~~~

原因

原因是在ADT20中添加了一个Lint检查:
Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.
这个Lint检查的是确保内部类Handler不会持有外部类的隐式对象,我们一般的Handler确实就是这样用的,所以正好落入套中。
当然我们可以关闭这个Lint检查,位于Settings->Editor->Inspections->Android->Lint->Performance->Handler reference leaks,去掉后面的勾即可,但是Lint毕竟是为我们好,再说了万一真的会有内存泄露发生呢?
那到底有没有内存泄露发生呢?有可能。
因为如果Handler位于主线程,则使用的是主线程的Looper和MessageQueue,那么每一个Message的target就是这个Handler,持有这个Handler的引用,假设这个时候GC要回收当前的Activity或者Service,但是由于Message太多处理不过来,或者Message延迟过大导致等待,那么这个Handler则不会被回收,因为它被Message引用,而同时我们的Handler又是个内部类,持有外部Activity或者Service的引用,而且又不是static的,那么外部Activity或者Service也不会被回收,所以就释放不了啦,泄露啦。
使用弱引用之后,Handler和外部的Activity或者Service的引用性变低,就好像以前用钢丝绳困在一起的,现在换棉线了,GC的时候就一定会回收掉弱引用包装的对象,这个是弱引用的特点,不太懂的话就去看看Java弱引用的相关资料。
That’s All!

你可能感兴趣的:(Android填坑)