android 避免误用context导致内存泄漏
android系统的应用程序(至少T-Mobile G1)被限制16M堆大小范围内。设备拥有很多的内存但是开发者想要得到却很少。即使你不想使用设备所有的内存,你也应该在不杀死其他应用程序的情况下使 用最少(的内存)。越多的程序在内存中,用户切换程序的速度就越快。在我的一部分工作中,我遇到一些内存问题他们大部分都源于一个错误:保持长时间引用Context(简单说就是Context泄露)。
android系统里,Context被常用来加在和使用资源。这也是为什么很多Widget在够找函数中接受一个Context的参数了。在 一个通常的android应用里,你经常可以使用两个Context(Activity和Application)。开发者通常会传递Context参数 到一个类和一个方法中:
@Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); setContentView(label); }
把activity的context传递给view,意味着view拥有一个整个activity的引用,进而引用activity占有的任何资源
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);
}
上述代码十分错误。当第一个屏幕方向发生改变的时候,他会泄露第一个activity。当把图片附在一个View的时候,Drawable的回掉函 数callback()引用View(事实上在setBackgroundDrawable函数里,发生 sBackgroud.setCallBack(label))。在整个代码片段里面,这个drawable对象用户一个包含activity对象引用的 TextView的引用。
这个范例是一个最简单泄露Context的例子,你可以去Home screen’s source code代码里面看看:当activity被销毁的时候,设置被存储drawable的callbacks为null.很有趣的是,许多你创建了一个链式 的被泄露的Context是十分糟糕的。他们让你相当快的消耗内存。
有两种方式可以避免Context相关的内存泄露。最常用的一种做法就是避免在范围外引用context.上面的例子就是显示了错误例子。第二个解决办法就是使用Application 的Context。这个Context的生命周期跟你的应用的生命周期一样长,并且不依赖于activities的生命周期。如果你需要Context来保存一个生命周期长的对象,记住使用application 的 context.你可以轻松使用Context.getApplicationContext()或者 Activity.getApplication()来得到。
总的来说,要避免Context相关的内存泄露,记住一下几点:
1.不要让生命周期长的对象引用activity 的context。(activity的引用应该和它本身有一样的生命周期)
2.尽量使用application-context代替activity-context
3.如果你不能控制他们的生命周期,避免使用高非静态内部类。使用静态内部类,并在activity对它们弱引用。因为非静态内部类的对象实例化时候默认包含了它的外部类的引用。