zoukankan      html  css  js  c++  java
  • Handler系列之内存泄漏

      本篇简单的讲一下平常使用Handler时造成内存泄漏的问题。

      什么是内存泄漏?大白话讲就是分配出去的内存,回收不回来。严重会导致内存不足OOM。下面来看一下造成内存泄漏的代码:

    public class MemoryLeakActivity extends Activity {
    
        private MyHandler mHandler;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
    
            mHandler = new MyHandler();
            mHandler.sendEmptyMessage(1);
        }
    
        private class MyHandler extends Handler{
            
            public MyHandler(){
            }
            
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        }
    }

    上面的代码我们不用管发送消息、接受消息,因为之前已经详细讲过了,不是本篇的重点。本篇我想说上面的代码会造成内存泄漏,什么意思?Handler持有MemoryLeakActivity引用,为什么?如果不持有当前类的引用,我怎么更改当前类的ui或其他逻辑???或者我们知道内部类持有外部类引用也行。那么怎么解决那?

      解决办法:将内部类改为静态内部类,因为静态内部类不持有外部类引用。由于Handler不再持有外部类引用,导致程序不允许你在Handler中操作Activity中的对象了。所以你还需要在Handler中增加一个对Activity的弱引用(使用弱引用的好处在于:activity一旦被置为null,他就会被立刻回收)。上面持有的引用属于强引用,强引用的特点就是当当前类被回收的时候,如果它被强引用所持有,那么当前类是不会被回收的!!!所以我们改成软引用持有当前类对象,这样在GC回收时会忽略掉弱引用,即就算有弱引用指向某对象,该对象也会在被GC检查到时回收掉。

    public class MemoryLeakActivity extends Activity {
    
        private MyHandler myHandler;
    
        private static final int ACTION_GOTO_MAIN = 1001;
        private static final int GOTO_MAIN_TIMER = 2 * 1000;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler);
            myHandler = new MyHandler(this);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            if (myHandler != null) {
                myHandler.sendEmptyMessageDelayed(ACTION_GOTO_MAIN, GOTO_MAIN_TIMER);
            }
    
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (myHandler != null && myHandler.hasMessages(ACTION_GOTO_MAIN)) {
                myHandler.removeMessages(ACTION_GOTO_MAIN);
            }
    
        }
    
        protected static class MyHandler extends Handler {
            private WeakReference<MemoryLeakActivity> mActivity;
    
            public MyHandler(MemoryLeakActivity activity) {
                mActivity = new WeakReference<MemoryLeakActivity>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                MemoryLeakActivity activity = mActivity.get();
                if (activity == null)
                    return;
                if (msg.what == ACTION_GOTO_MAIN) {
                    //处理逻辑
                }
            }
        }
    }

    上面代码很好的解决了内存泄漏的问题。但是这段代码可能会在很多界面都会遇到,难道每个界面都需要这样写吗?重复的工作啊,所以干脆我们抽取成一个基类,将来创建Handler的时候继承这个基类就好。

    public abstract class WeakHandler<T> extends Handler {
    
        protected WeakReference<T> reference;
    
        //创建子线程Handler使用的构造器
        public WeakHandler(Looper looper, T reference) {
            super(looper);
            this.reference = new WeakReference<>(reference);
        }
    
        //创建主线程Handler使用的构造器
        public WeakHandler(T reference) {
            this.reference = new WeakReference<>(reference);
        }
    
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            T t = reference.get();
            if (t == null)
                return;
            handleMessage(t, msg);
        }
    
        protected abstract void handleMessage(T t, Message message);
    
    }

    上述代码,我们使用了泛型,这个泛型就是我们之前说的当前类,同时提供了两种构造器,这样不管我们是创建主线程还是非主线程Handler对象时,都不会造成内存泄漏了。

      至此,Handelr系列讲解到此结束,大多数都是参数慕课网的《Android面试常客Handler详解》,我这里只是将视频中的内容加上自己的理解纪录下来,希望对大家有所帮助。

  • 相关阅读:
    DRF 分页
    DRF 权限 频率
    DRF 版本 认证
    opencl(6)读写传输命令、内存映射命令
    opencl(5)缓存对象
    opencl(4)命令队列
    opencl(3)程序、内核
    opencl(2)平台、设备、上下文的获取与信息获取
    epoll
    unsigned 变量名:n
  • 原文地址:https://www.cnblogs.com/lang-yu/p/6230368.html
Copyright © 2011-2022 走看看