android-不容易发现的内存泄漏

来源:互联网 发布:农村淘宝是做什么的? 编辑:程序博客网 时间:2024/05/16 17:09

一、Handler引起的泄漏

假如程序如下方式书写:

Handler mHandler = new Handler() {        @Override        public void handleMessage(android.os.Message msg) {            super.handleMessage(msg);        };    };

由于mHandler作为内部类,间接持有了对Activity的引用。所以当Activity即将要销毁的时候,如果mHandler消息没有及时处理完,就会导致Activity不能被释放。这样就导致了内存泄漏。

RE:可以通过Android studio中的静态检测工具来检测项目中可能存在的Handler泄漏

解决方式:1.优先使用静态的内部类 2.Handler使用弱引用

由于界面使用Handler比较多,所以通过一个自定义Handler来简化使用流程。代码如下:

/** *  * 更新UI的Handler基类 避免匿名自定义Handler,而导致的内存泄露 使用时定义静态内部类,该类简化了弱引用的使用流程 *  * @author ChenP * @date 2016年8月29日 上午11:04:32 */public class BaseUIHandler<T> extends Handler {    /**     * UI界面对象的弱引用对象     */    protected WeakReference<T> refInstance;    /**     * 构造函数     *     * @param target     *            UI界面对象实例     */    protected BaseUIHandler(T target) {        refInstance = new WeakReference<T>(target);    }    /**     * 获取UI对象实例(根据弱引用对象获取,不会导致内存泄露)     *      * @return     * @return T     * @author ChenP     * @date 2016年8月29日 上午11:05:22     */    protected T get() {        return refInstance.get();    }}

这样在界面中使用的时候,

static class UIHandler extends BaseUIHandler<CldAndActivity> {        protected UIHandler(CldAndActivity target) {            super(target);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            CldAndActivity instance = get();            if (instance == null) {                return;            }            switch (msg.what) {            case 0:                /**                 * 处理hanlder事务。----由于静态内部类不能访问外部类的方法和变量,可以通过对instance的引用来处理。                 * 比如写一个dealHandler()方法,通过instance.dealHandler()来处理。                 */                break;            }        }    }

二、静态的成员变量(如果Drawable)引起泄漏

private static Drawable sBackground;    @Override    protected void onCreate(Bundle state) {        super.onCreate(state);        TextView label = new TextView(this);        label.setText("Leaks are bad");        if (sBackground == null) {            sBackground = getDrawable(R.drawable.large_bitmap);        }        label.setBackgroundDrawable(sBackground);        setContentView(label);    }   

label.setBackgroundDrawable这个方法内部会调用 d.setCallback(this);持有对TextView的引用。但是在4.0之后才使用弱引用

    public final void setCallback(Callback cb) {        mCallback = new WeakReference<Callback>(cb);    }

所以在4.0之前如果是静态的Drawable,持有对Activity的引用。就会导致内存泄漏

解决方式:在Activity将要onDestroy的时候,调用sBackgroundDrawable.setCallback(null)。


三、非静态内部类的静态实例容易造成内存泄漏

public class MainActivityextends Activity  {           static Demo sInstance = null;      @Override      public void onCreate(BundlesavedInstanceState)      {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          if (sInstance == null)          {             sInstance= new Demo();          }      }      class Demo      {      voiddoSomething()      {                 System.out.print("dosth.");      }      }  }

RE:Demo作为非静态内部类,持有对Activity的应用。静态的成员变量持有对Activity的引用,就会导致Activity不能回收。


四、单例模式、外部API保存了类、上下文Context的引用

Test.getInstance().init(new TestProgressListener ());private class TestProgressListener implements ProgressListener {        /**         * @see com.cld.nv.frame.ICldProgressListener#onStart()         */        @Override        public void onStart() {        }    }

如果单例模式、其他API内部保存了对非静态内部类or上下文Context的引用。也会间接导致持有对Activity的引用。导致内存泄漏


参考链接:Android内存泄漏分析及调试(里面有MAT和DDMS工具的使用)

0 0