Android应用程序生命周期和单例模式

4

大多数人都熟悉这种模式:

   public class MySingeltone {

    public String mSomeReferenceTypeData;
    public int mSomeValueTypeData;

    private static MySingeltone mInstance;

    private MySingeltone() {

    }

    public static MySingeltone getInstance() {
        if (mInstance == null) {
            mInstance = new MySingeltone();
        }

        return mInstance;
    }
 }

我遇到的问题是,最近发现mInstance在活动被销毁后不等于null,或者整个应用程序被关闭时,例如:

public class SomeActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        MySingeltone mySingeltone = MySingeltone.getInstance();
        mySingeltone.mSomeReferenceTypeData = "some value";
    }
}

在关闭所有应用程序运行的活动(比如10秒后..)后,下次启动“SomeActivity”时,mInstance仍然保留着相同的引用,并且其字段上的值也相同。

为什么会这样?

我错过了什么?

Android何时回收属于应用程序的静态成员?


你在哪里检查单例是否为同一个实例? - Jazzy Josh
@Jazzy Josh:你可以通过在设置新值之前获取该值来简单地查看它。在我的示例中,它将位于getInstance方法和下一行之间。只需要检查它不等于null,因为第一次启动时该值仍将为null。 - Tal Kanel
我特别指的是应用程序中的哪个位置。如果您的Activity从未被销毁,那么您将从onStop转到onRestart和onStart,而不是通过onDestroy被杀死,这样您的Singleton仍将存活。 - Jazzy Josh
这就是它应该的样子。所以它是静态单例。但我遇到了相反的情况:当持有Activity引用的对象被销毁时,单例也消失了!为什么? - Arvis
@TalKanel,我的意思是当下一次引用它时,实例变为null并已重新实例化。应用程序进程仍处于活动状态。如果应用程序也被终止了,那么就没有关系了 - 在这种情况下,所有变量都将重新初始化和实例化为第一次。 - Arvis
显示剩余5条评论
3个回答

5

"mInstance"是一个静态变量,当你关闭应用程序时它不会变为null。关闭应用程序并不意味着你的应用程序已被销毁。

此外,Android应用程序没有关闭的概念。如果你退出应用程序,它不会立即被销毁。当Android操作系统决定关闭不再使用的应用程序时,它会在内部处理。在内存短缺的情况下,当Android决定销毁应用程序时,这个静态变量也会变为null。


3
这个答案是错误的,如果内存已满并且Android操作系统决定清除他的应用程序,那么下一次他尝试使用它时,这个变量也将为空。 - Ofek Ron

2

您无法精确控制Java对象何时被垃圾回收。当没有更多的(非循环)引用指向该对象时,该对象就有资格进行垃圾回收。 此外,在Android中,您也无法控制Activity何时从内存中删除。


那么这是否意味着,如果我希望我的单例类在某个活动创建时为null,我需要在onDestroy()方法中将其设置为null或类似的操作吗? - Tal Kanel
@Tan Kanel 是的。但是你想要销毁一个单例确实有些奇怪,因为单例应该代表一直存在的东西。也许你的单例里应该有一些 open()/close()/isOpened() 方法,或者它应该是一个服务。 - Alexander Kulyakhtin
是的,你说得对,我有点这么做,但我更多地是为了原则而问。 - Tal Kanel

0
为什么会发生这种情况?我错过了什么吗?当安卓垃圾回收应用程序的静态成员时会发生什么?
首先,如其他人所说,Android 没有关闭应用程序的概念,因为 Android 操作系统自己管理应用程序进程的生命周期。
其次,你做了错误的测试 - 如果不是关闭所有应用程序,而是相反地通过启动越来越多的应用程序来填充内存,那么最终你的应用程序的内存将被清理以供其他应用程序使用,其中包括所有静态成员和实例成员!然后,你会发现静态变量将为空,就像你期望的那样。
它们只是“懒洋洋”地清理内存,如果有足够的内存,那么你的应用程序可能永远不会被清理。
实际上,据我所知,没有任何方法可以保证对象在任何时刻都不会从设备内存中清除。在某些情况下,这会导致不良行为。例如,如果单例在创建时进行了大量处理,则调用getInstance 可能会使你的UI卡住,甚至由于不负责任而导致应用程序崩溃。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接