包含引用好/坏的属性

时间:2012-12-04 12:53:36

标签: android

我是Android / Java的新手(通常使用PHP和JavaScript)。我已经阅读了一些关于应用程序内存泄漏问题的文章,当引用被错误地使用时,所以我对我在其他人的工作中经常看到的问题有疑问。

很多人,当他们需要访问诸如Views之类的东西时,在多个方法中,会在创建活动期间分配的属性中保留对此的引用。根据我的阅读(或者至少了解我所读过的内容),这是内存泄漏的课程之一?

为对象分配ID然后在每种方法中搜索它们会更好吗?如果是这样,那么动态创建的对象呢?

4 个答案:

答案 0 :(得分:2)

如果你正确使用它们会很好,如果不正确则会很糟糕。

如果您将活动之外的内容传递给另一个类,并且该类的生命周期大于活动的生命周期,则只会泄漏。一旦它不再是前台活动,Android可能会破坏你的活动,如果活动之外的东西持有对它的引用,那么垃圾收集器就无法将内存释放回堆中。

特别注意活动背景,静力学和单身人士。

简单地保持对活动内部视图的引用是绝对正常的。

这是一个坏的例子(伪代码);

public class MyApplication extends Application{
    public static ImageView activityBackgroundImageView;
}

public class MyActivity extends Activity{

    ImageView iv = findViewById(R.id.myImageView);
    myApplication.activityBackgroundImageView= iv; // <==== LEAK

}

实际上,泄漏不在那里,它只会在(如果)myActivity完成()或被破坏时泄漏。

每个对象都有一个引用计数 - 有多少对象拥有对它的引用。在活动中设置对ImageView的引用后,引用计数为1。然后,将该引用复制到Application类。 NB。 Java中的所有内容都是按值传递的,因此您传递引用的值,恰好是值的副本 - 即对同一对象的新引用。 ImageView上的引用计数现在是两个。

稍后,您完成()您的活动,并且引用计数递减。它现在是一个。垃圾收集器无法释放该ImageView对象,因为它具有非零引用计数。

当然,你可以通过在应用程序中清空引用来修复它,但现在你有了意大利面条代码。

答案 1 :(得分:0)

在Android中引用的泄漏问题发生在对<{1}}}对象的引用的事物的引用由绑定到UI的事物所持有时。在其包含的活动中保持对视图的引用,因为在某些时候系统中的任何内容都不会引用该活动(在Context之后),并且因为不再从垃圾收集根引用它(像一个全局变量),它有资格进行垃圾收集。换句话说,一旦没有人 else 拥有对该活动的引用,活动及其视图之间设置的循环引用就不再重要。

问题出现的地方是在UI和活动生命周期调用之外发送对活动的引用 - 其本身 onDestroy()。像位置监听器或您忘记取消注册的东西。这将保留该引用,使整个树不符合垃圾收集的条件。因此,大泄漏。

答案 2 :(得分:0)

您对内存泄漏原因的观察并不完全正确。

存储对视图元素的引用非常好,它是如何执行此操作并使用它们可能导致内存泄漏。例如,避免使用静态引用,例如,如果您静态引用位图图像,您可能会无意中导致垃圾收集问题,正如Simon在答案中指出的那样。

所以可以做到以下几点。

class{
 private TextView myTextView;

onCreate()
 myTextView = findViewById(R.id.mytextview);

myMethod()
 myTextView.text = "hello view."

}

myMethod纯粹为了方便而使用现有的引用,没有什么可以阻止你放置

findViewById(R.id.mytextview).text = "hello view";

然而,如果您有很多引用,这将导致真正无法读取的代码。所以你可以使用局部范围变量。

myMethod()
 TextView myTextView = findViewById(R.id.mytextview);
 myTextView.text = "Hello"
 .....

根据您的个人喜好,它不一定会导致内存泄漏。

现在问题是findViewById是一个密集的过程,所以你真的不想重复调用它。列表视图特别容易出现这种情况,如果您不满足此要求,则会显着减慢。

因此,在列表视图中,您会发现人们实现了一个viewHolder模式。您为视图子元素指定引用的小对象。然后将此对象分配给父视图Tag属性。在对视图的后续调用期间,您将测试以查看视图标记属性是否具有viewHolder,如果是,它将具有对子对象的引用,从而节省您每次需要更新视图内容时调用findViewById的时间和精力。 / p>

非常粗略的想法,它的实施略有不同。     viewHolder = new ViewHolder();     viewHolder.myTextField = findViewById(R.id.mytextview);     myView.setTag(viewHolder)     ....     if(viewHolder)      viewHolder.text =“你好”

请注意,您只能在列表视图中使用它。我没有把它当作一般的经验法则。

查找列表视图适配器的高效视图持有者模式。

答案 3 :(得分:0)

感谢您的回答,只是想在创建一个会给人们带来问题的应用之前确定。

作为安全措施,我添加了onStop和onRestart来删除和重新创建引用。虽然我从不在静态属性中使用引用,但这应该确保在应用程序处于后台时不存在任何此类类型。

相关问题