Android内存优化-方式三:函数需要传递Context参数时,避免直接传递Activity

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yaoming168/article/details/88946570

Android上 ,Context可以用于很多操作,但是大部分时候是用来加载以及使用资源。这就是为什么所有的widgets在他们的构造函数中接受一个Context参数。在一般的android应用中,通常有两种Context:分别是Activity和Application。通常的,当咱们的类和方法需要使用到context时,咱们传递的是Activity这个context:
当某些View/方法需要Context对象时经常会传入Activity当作Context,如果这时里面对这个Context的占有是整个APP声明周期的,那么就会造成内存泄漏。这个Activity就不能被及时回收。
1、用Application代替Activity 因为Application跟APP的生命周期相同会一直存在。
2、避免调用者的静态引用。
3、不需要时释放掉这个引用。
Android上 ,Context可以用于很多操作,但是大部分时候是用来加载以及使用资源。这就是为什么所有的widgets在他们的构造函数中接受一个Context参数。在一般的android应用中,通常有两种Context:分别是Activity和Application。通常的,当咱们的类和方法需要使用到context时,咱们传递的是Activity这个context:

@Override
protected void onCreate(Bundle state)
{
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}

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

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,这个在第一次屏幕改变时被创建的activity。当一个Drawable被关联到一个view上,这个view就相当于在drawable上设置的一个回调。在上面的代码片段中,这表示drawable有一个TextView的引用,而这个TextView又拥有一个activity的引用(Context),activity依次引用了几乎所有的东西(取决于自己的代码)。
  这个例子展示了一个最简单的Context 泄漏的情况,可以在Home screen 的源码中看到咱们是如何解决这个问题的( 查找unbindDrawables() 方法) ,这就是当activity 被销毁的时候将drawables 的回调设为null 。有趣的是,可能创造出一系列context泄漏的情况有很多,这非常糟糕。他们会是很快内存溢出。
  有两种简单的方法来避免context 相关的内存泄漏。最显著地一个是避免context 逃出他自己的范围之外。上面的例子就展示了使用静态引用的情况,而内部类和他们对外部类的的隐式引用也是同样危险的。第二种方法是使用Application context 。这个context 的生存周期和应用的生存周期一样长,而不是取决于activity 的生存周期。如果想保持一个长期生存的对象,并且这个对象需要一个context ,记得使用application 对象。可以通过调用Context.getApplicationContext() or Activity.getApplication() 来获得。
  总而言之,想要避免context 相关的内存泄漏 ,记住以下几点:
  A:不要对activity 的context 长期引用( 一个activity 的引用的生存周期应该和activity 的生命周期相同)
  B:试着使用关于application的 context 来替代和activity相关的context
  C:如果一个acitivity 的非静态内部类的生命周期不受控制,那么避免使用它;使用一个静态的内部类并且对其中的activity 使用一个弱引用。解决这个问题的方法是使用一个静态的内部类,并且对它的外部类有一WeakReference,就像在ViewRoot中内部类W所做的就是这么个例子。

猜你喜欢

转载自blog.csdn.net/yaoming168/article/details/88946570
今日推荐