程序员人生 网站导航

避免长期持有了一个Context的引用造成内存泄露

栏目:综合技术时间:2015-05-14 09:12:21

    Android上 ,Context可以用于很多操作,但是大部份时候是用来加载和使用资源。这就是为何所有的widgets在他们的构造函数中接受1个Context参数。在1般的android利用中,你通常有两种Context:分别是Activity和Application。通常的,当我们的类和方法需要使用到context时,我们传递的是Activity这个context。

   

[java]
  1. @Override  
  2. protected void onCreate(Bundle state) {  
  3.   super.onCreate(state);  
  4.     
  5.   TextView label = new TextView(this);  
  6.   label.setText("Leaks are bad");  
  7.     
  8.   setContentView(label);  
  9. }  

    这意味着views具有1个对全部activity的援用,也就是援用了你的activity所具有的1切;通常的,这指的是完全的视图层级结构和所有它的资源。因此,如果你泄漏了1个Context(“ 泄漏 ”意味着你保持着它的1个援用,从而使它不能被垃圾回收机制回收),就意味着你泄漏了很多的内存。如果你不谨慎, 泄漏1 个activity的所有资源真的非常容易。
    当 屏幕的方向产生改变的时候,系统默许将会烧毁当前的activity并且创建1个新的activity同时保持着原本的状态。在做这个的时候,Android会从资源重新加载利用的UI。现在,想象1下你写了1个利用,这个利用有1张很大的bitmap。你不想再每次旋转的时候重新加载它。最简单的方法让bitmap延续作用而不随每个方向而重新加载 ,就是把它放进1个静态域:

[java]
  1. private static Drawable sBackground;  
  2.     
  3. @Override  
  4. protected void onCreate(Bundle state) {  
  5.   super.onCreate(state);  
  6.     
  7.   TextView label = new TextView(this);  
  8.   label.setText("Leaks are bad");  
  9.     
  10.   if (sBackground == null) {  
  11.     sBackground = getDrawable(R.drawable.large_bitmap);  
  12.   }  
  13.   label.setBackgroundDrawable(sBackground);  
  14.     
  15.   setContentView(label);  
  16. }  
    这段代码很快,但是毛病也很严重:它泄漏了第1个activity,这个在第1次屏幕改变时被创建的activity。当1个Drawable被关联到1个view上,这个view就相当于在drawable上设置的1个回调。在上面的代码片断中,这表示drawable有1个TextView的援用,而这个TextView又具有1个activity的援用(Context),activity顺次援用了几近所有的东西(取决于你的代码)。

这个例子展现了1个最简单的Context 泄漏的情况,你可以在Home screen 的源码中看到我们是如何解决这个问题的( 查找unbindDrawables() 方法) ,这就是当activity 被烧毁的时候将drawables 的回调设为null 。有趣的是,你可能创造出1系列context泄漏的情况有很多,这非常糟。他们会是你很快内存溢出。
     有两种简单的方法来避免context 相干的内存泄漏。最显著地1个是避免context 逃出他自己的范围以外。上面的例子就展现了使用静态援用的情况,而内部类和他们对外部类的的隐式援用也是一样危险的。第2种方法是使用Application context 。这个context 的生存周期和你的利用的生存周期1样长,而不是取决于activity 的生存周期。如果你想保持1个长时间生存的对象,并且这个对象需要1个context ,记得使用application 对象。你可以通过调用Context.getApplicationContext() or Activity.getApplication() 来取得。
      总而言之,想要避免context 相干的内存泄漏 ,记住以下几点:
          1、不要对activity 的context 长时间援用( 1个activity 的援用的生存周期应当和activity 的生命周期相同)
          2、试着使用关于application的 context 来替换和activity相干的context
          3、如果1个acitivity 的非静态内部类的生命周期不受控制,那末避免使用它;使用1个静态的内部类并且对                  其中的activity 使用1个弱援用。解决这个问题的方法是使用1个静态的内部类,并且对它的外部类有1                   WeakReference,就像在ViewRoot中内部类W所做的就是这么个例子。
         4、垃圾回收器不能处理内存泄
的保障

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐