Android--避免内存泄漏

避免内存泄漏
背景
Android应用最多可以使用16MB的堆内存
因此,要做到及时地释放应用所占用的内存资源,还要避免内存的泄漏
引起内存泄漏的主要原因:
Context索引的长期存在
两种类型的Context: Activity & Application
UI组件在构造方法中传入Context参数的原因:
Context可用于很多的操作,主要是访问应用的资源
例如:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TextView textView=new TextView(this);
    textView.setText("Hello world!");
    setContentView(textView);
}

TextView 拥有了一个她所属的Activity索引,也就代表它持有了所有的View层次结构及所有资源。
因此,如果泄漏了 Context,则泄漏了许多的内存。
(注意:泄漏,指的是长时间持有一个Context索引,阻止GC回收Context资源)
设备屏幕朝向发生改变—》系统销毁当前的Activity并创建新的Activity实例,同时维护他的状态—》Android重载UI
举例
编写一个应用,使用一个大的Bitmap,但是不想屏幕每次旋转都重载该Bitmap,那么可能会想到的最简单的是方式是把它保存到一个静态成员里,可能的代码如下:

private static Drawable sBackground;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TextView textView=new TextView(this);
    textView.setText("Hello world!");
    
    if(sBackground==null){
        sBackground=getDrawable(R.drawable.large_bitmap);
    }
    textView.setBackgroundDrawable(sBackground);
    setContentView(textView);
}

在第一次屏幕朝向改变时,它泄漏了第一个Activity,当一个Drawable绑定到一个View上时,View被设置为drawable上的callback。在上面的代码中,意味着sBackground具有一个TextView的索引,而TextView本身又拥有第一个Activity(Context)的索引,反过来Activity又拥有几乎所有对象的索引,这样就导致了内存的泄漏。
避免泄漏
避免跨越下文(最常见的)
使用应用上下文
–上下文在应用存活期间一直存在,不依赖activity生命周期
3.可以通过Context.getApplicationContext()或者Activity.getApplication()获得应用上下文对象
总结
避免泄漏的几种方法:
不长时间保存Activity相关的上下文索引
尝试使用应用上下文,而不是activity上下文
在一个activity中,如果不控制非静态内部类的生命周期,那么避免使用它,使用一个静态内部类,在内部创建一个activity的weak索引。例如ViewRoot中的W内部类的就是这样做的:

static class W extends IWindow.Stub {
    private final WeakReference<ViewRoot> mViewRoot;
    public W(ViewRoot viewRoot,Context context){
        mViewRoot=new WeakReference<ViewRoot>(viewRoot);
    }
    public void resized(int w, int h, Rect converedInsets, Rect visiableInsets, boolean reportDraw, Configuration newConfig){
        final ViewRoot viewRoot=mViewRoot.get();
        ...
    }
}

4.垃圾回收器并不是防止内存泄漏的保险。

例子

public class BaseApplication extends Application {
    static Context mContext;
    static Handler sHandler;

    //static 代码段可以防止内存泄露
    //用到第三方的刷新开源框架
    static {
        //设置全局的Header构建器
        SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {
            @Override
            public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
                layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);
                return new MaterialHeader(context);//.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header,默认是 贝塞尔雷达Header
            }
        });
        //设置全局的Footer构建器
        SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {
            @Override
            public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
                //指定为经典Footer,默认是 BallPulseFooter
                return new ClassicsFooter(context).setDrawableSize(20);
            }
        });
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
        sHandler = new Handler();
 
        CrashReport.initCrashReport(getApplicationContext(), "340280f0zb", false);
        //使用崩溃收集功能
        Thread.setDefaultUncaughtExceptionHandler(new MyUnCaughtExceptionHandler());


    }

    public static Context getContext() {
        return mContext;
    }

    public static Handler getHandler() {
        return sHandler;
    }

    class MyUnCaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            CrashReport.postCatchedException(ex, thread);

            new Thread(){
                @Override
                public void run() {
                    ActivityUtils.finishAllActivities();
                    Intent intent=new Intent(BaseApplication.getContext(),MianActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                    android.os.Process.killProcess(android.os.Process.myPid());
                }
            }.start();

        }
    }
}

【完】


你可能感兴趣的:(Android,内存泄漏)