在android中context能够做不少操做,其主要的功能是加载和访问资源。android有两种不一样的context,一种是 application context,另一种是activity context,一般咱们在各类类和方法间传递的是activity context。 好比一个activity的onCreate:android
1. protected void onCreate(Bundle state) {app
2. super.onCreate(state);this
3. TextView label = newTextView(this);code
4. //传递context给view control对象
5. label.setText("Leaks are bad");生命周期
6. setContentView(label);图片
7. }内存
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。 这样若是context发生内存泄露的话,就会泄露不少内存。 这里泄露的意思是gc没有办法回收activity的内存。 Leaking an entire activity是很容易的一件事。 当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再建立一个新的。 好比咱们写了一个应用程序,它须要加载一个很大的图片,咱们不但愿每次旋转屏 幕的时候都销毁这个图片,从新加载。实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类建立销毁它始终保存在内存中。 实现相似:资源
1. public class myactivity extends Activity {get
2. private static Drawable sBackground;
3. protected voidonCreate(Bundle state) {
4. super.onCreate(state);
5. TextView label = new TextView(this);
6. label.setText("Leaks are bad");
7. if (sBackground == null) {
8. sBackground = getDrawable(R.drawable.large_bitmap);
9. }
10. label.setBackgroundDrawable(sBackground);
11. //drawable attached to a view
12. setContentView(label);
13. }
14. }
这段程序看起来很简单,可是却存在很严重的问题。当屏幕旋转的时会有leak(即gc无法销毁activity)。 咱们刚才说过,屏幕旋转的时候系统会销毁当前的activity。可是当drawable和view关联后,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能销毁,它所引用和间接引用的都不能销毁,这样系统就没有办法销毁当前的activity,因而形成了内存泄露。gc对这种类型的内存泄露是无能为力的。 避免这种内存泄露的方法是避免activity中的任何对象的生命周期长过activity,避免因为对象对 activity的引用致使activity不能正常被销毁。咱们可使用application context。application context伴随application的一辈子,与activity的生命周期无关。application context能够经过Context.getApplicationContext或者Activity.getApplication方法获取。 避免context相关的内存泄露,记住如下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity自己生命周期是同样的。
2. 对于生命周期长的对象,可使用application context 。
3. 避免非静态的内部类,尽可能使用静态类,避免生命周期问题,注意内部类对外部对象引用致使的生命周期变化。