Handler是安卓中常见的实现异步操作的方法,使用简单,但是操作不注意很容易造成内存泄漏。

在使用Handler的时候,我们常将Handler定义为内部类,也可以单独一个类定义一个Handler,单独定义是不会持有activity引用的,所以不会造成内存泄漏,而在使用内部类的时候,会持有activity的引用,当activity finish掉的使用,Handler仍然持有该activity的引用,这就造成了内存泄漏的原因。

讲讲如何解决Handler定义为内部类所造成内存泄漏的解决方案。

根据官方提示,需要将内部类申明为static 静态内部类,再使用弱引用获取外部类对象。

因为内部类默认持有外部类的引用,就默认持有activity的引用,而静态内部类则不会;而之所以要使用弱引用,只是因为我们需要用到外部类的变量和方法,所以需要一个外部类对象,而使用弱引用的话就不会持有外部类引用。

下面看例子,正常会造成内存泄漏的写法如下:

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
 
        }
    };
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handleroom);
 
        findViewById(R.id.btn_send).setOnClickListener(this);
        tv = findViewById(R.id.tv);
 
        // 延时5min发送一个消息,此时handler是持有activity引用的
        mHandler.sendEmptyMessageDelayed(1, 5 * 60 * 1000);
    }

测试结果可以通过横竖屏切换,然后观察AS控制台内存占用数据即可知晓。

下面是使用static跟弱引用的写法:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handleroom);
        
        findViewById(R.id.btn_send).setOnClickListener(this);
        tv = findViewById(R.id.tv);

        MyHandler handler = new MyHandler(this);
        handler.sendEmptyMessageDelayed(0, 5 * 60 * 1000);
    }
 

    private static class MyHandler extends Handler {
        private WeakReference<HandlerOOMActivity> weakReference;
        private HandlerOOMActivity activity;
 
        public MyHandler(HandlerOOMActivity activity) {
            weakReference = new WeakReference<>(activity);
            this.activity = activity;
        }
 
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Log.e(TAG, "handleMessage: ");
            HandlerOOMActivity activity = weakReference.get();
            switch (msg.what) {
                case 0:
                    break;
            }
        }
    }

同样可以观察AS控制台内存占用数据,与未申明为static做对比即可知道。

还有一种请况,Handler在消息处理完后,是会被系统随时回收的,那么即使我们在用内部类的时候,在持有外部类引用的情况下,只要在外部类销毁的时候,让Handler把所有的消息都处理完,即调用Handler的removeCallbacksAndMessages,也是可以避免内存泄漏的。但是一般还是建议采用静态内部类+弱引用的方法。

如何避免Handler引起的内存泄漏,总结三点信息如下:
 1、使用static 修饰内部类handler,但是一般会弱引用activity对象,因为要使用activity对象中的成员
 2、使用单独定义handler,同样可以弱引用activity
 3、可以使用内部类的handler,但是在activity销毁的时候在onDestroy方法中调用Handler的removeCallbacksAndMessages方法

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐