【问题标题】:Using static variables in Android在 Android 中使用静态变量
【发布时间】:2011-01-29 09:04:56
【问题描述】:

在 android 中,是否推荐使用静态变量? 例如,在 Java 中实现 单例模式,我通常会这样做:

private static A the_instance;
public static A getInstance() {
    if (the_instance == null) {
       the_instance = new A();
    }
    return the_instance;
}

另外,Android JVM 什么时候清理这个问题?

【问题讨论】:

  • 我相信你需要一个锁来同步你的单例类,否则在多线程场景下你将在堆内存上有多个对象。

标签: java android dalvik


【解决方案1】:

static 字段作为一个整体附加到Class 实例,而该实例又附加到加载类的ClassLoader。当整个 ClassLoader 被回收时,the_instance 将被卸载。我有 90% 的把握当 Android 破坏应用程序时会发生这种情况(不是当它进入后台或暂停,而是完全关闭时。)

因此,只要您的应用运行,就可以将其视为存在。辛格尔顿是个好主意吗?人们有不同的看法。我自己认为适当使用时很好。我认为答案在 Android 上变化不大。内存使用本身不是问题;如果你需要在内存中加载一堆东西,那要么是个问题,要么不是,不管你是否将数据封装在一个 Singleton 中。

【讨论】:

  • 已确认,它将一直保留到您的整个进程被销毁为止。当您的进程恢复时,您的单例将重新出现!
  • 需要注意的是,单例会重新创建,但不会自动恢复单例的原始状态。这必须手动完成。
  • @harshjv 单例通常也被设计为不可变的,在这种情况下,您是否看到它的旧副本或新副本都没有关系。但是如果你的单例保持状态,当单例被销毁时,该状态就会丢失。它被重新创建,但具有默认的初始状态。
  • @harshjv,肖恩·欧文是正确的。当进程被销毁时,单例也被销毁。当进程恢复时,单例将自动重新创建。但是,单例的任何属性或底层私有成员变量都不会自动恢复。您必须分别投入工作以保存和恢复对象的状态。
  • 如果您的代码将单例初始化为具有类似于您的字符串列表的状态,那么每次创建它时它当然都会具有这种状态。如果您的代码以某种方式更改了该状态,例如添加到列表中,则不会重新创建这些状态。这与 JVM 中的所有其他对象相同。
【解决方案2】:

我认为静态变量还可以。

这是 Android 文档所说的:

http://developer.android.com/guide/appendix/faq/framework.html

如何在单个应用程序中的活动/服务之间传递数据?

公共静态字段/方法

使数据可跨活动/服务访问的另一种方法是使用公共静态字段和/或方法。您可以从应用程序中的任何其他类访问这些静态字段。要共享一个对象,创建对象的 Activity 会设置一个静态字段以指向该对象,而任何其他想要使用该对象的 Activity 只需访问该静态字段。

【讨论】:

  • 绑定、回调/监听器,但不是静态的
  • 您听说过意图吗?静态字段是不好的做法,它往往会紧密耦合......
  • 你们能否为我提供合适的解决方案?使用静态变量时,当应用程序来自后台或保持打开数小时时,我会遇到问题,它会崩溃。有意图地很难通过对象。那么这样做的正确方法是什么?
  • @SagarPanwala 尝试使用 Parcelables。如果您有对记忆产生巨大影响的大型位图,请尝试使用合适的库,例如 Picasso。
  • @SagarPanwala 您能否提供有关崩溃的更多详细信息?
【解决方案3】:

与其他人所说的相反 - 这还不错。当然,它有一些结构。在官方 googlesamples/android-architecture 存储库中,它在 todo-mvp-clean 下使用(Todo 应用程序实现 MVP 模式并遵循清洁架构原则)。 看看这个file

您可以看到很多引用单例 getter 的静态方法。

Dagger DI 框架是现代、不易出错且方便的替代方案。

【讨论】:

    【解决方案4】:

    我不确定这种方法是否适用于您可用内存有限的移动平台。更不用说该应用程序将在支持多任务的设备上运行。

    我认为,这种方法可能会占用设备的内存,但我没有文档支持这一点。也许比我受过更多教育的人可以分享他们的想法。

    【讨论】:

    • 我不认为这实际上可能是一个问题,因为 DVM 很好地管理它的内存。
    【解决方案5】:

    没有。不要这样做! Singleton is an anti-patern!。相反,使用依赖注入,无论是通过框架(例如通过DaggerRoboguice)还是通过显式传递实例化对象。

    【讨论】:

    • 请记住,核心 Android 团队提倡使用您的“反模式”,而且 Google Guice 似乎需要大约 800KB 的 JAR,这对于移动应用来说是不利的。
    • Guice 很棒,但对于许多应用程序来说可能有点过头了。但是,如果您打算深入 Guice,请查看这个精美的项目:code.google.com/p/roboguice
    • 依赖注入的东西带来了复杂性。我见过一些开发人员花费数小时来找出注入错误对象的原因。单身人士有它的价值!
    • @yonexbat 框架确实带来了复杂性,但也可以执行显式注入(无需框架),这是可以理解的。然而,两者仍然比使用单例更好,这使得代码不灵活且难以测试。请参阅我的链接,了解为什么单例是反模式并且应该避免的理由。
    • 您在这里对单例模式的看法做出了一个脆弱的假设,即使用私有构造函数会导致单个实例。不是这种情况。在静态对象实例创建方法的实现中,单个实例是策略而不是语言强制执行,例如:“getInstance”。您可以让此方法返回任意数量的实例,也可以返回一个,具体取决于您对类的打算。
    猜你喜欢
    • 1970-01-01
    • 2017-05-13
    • 2011-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多