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


一、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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值