这两种机制各有什么优劣?
说实话,我期望在这篇针对Web应用程序的Singleton模式,不是一个好主意!但应用于Android上会得到相同的答案。 我对吗?除此之外DalvikVM有什么不同?
编辑:我想听取涉及的几个方面的意见:
- 同步
- 可重用性
- 测试
我非常不同意Dianne Hackborn的回复。我们正在逐步从我们的项目中删除所有单例,转而使用轻量级、任务作用域对象,当您实际需要它们时可以轻松重新创建。
单例对于测试来说是一场噩梦,如果懒惰初始化,会引入“状态不确定性”,产生微妙的副作用(当将调用getInstance()从一个作用域移动到另一个作用域时可能会突然出现)。可见性被提及为另一个问题,由于单例意味着对共享状态进行全局(=随机)访问,因此在并发应用程序中未正确同步时可能会出现微妙的错误。
我认为这是一种反模式,它是一种糟糕的面向对象风格,本质上相当于维护全局状态。
回到你的问题:
虽然应用上下文本身可以被视为单例,但它是由框架管理的,并具有明确定义的生命周期、范围和访问路径。因此,我认为如果您确实需要管理应用程序全局状态,则应该使用此处而不是其他地方。对于其他任何事情,请重新考虑是否真正需要单例对象,或者是否也可以重写您的单例类以实例化执行手头任务的小型、短暂对象。
我非常推荐使用单例模式。如果你有一个需要上下文的单例,可以这样写:
MySingleton.getInstance(Context c) {
//
// ... needing to create ...
sInstance = new MySingleton(c.getApplicationContext());
}
我更喜欢使用单例模式而不是Application类,因为它可以使应用程序更加有条理和模块化。相比于需要在整个应用程序中维护所有全局状态的一个地方,每个单独的部分都可以自己管理。此外,单例模式的延迟初始化(按需初始化)让你不必在Application.onCreate()中做所有的初始化工作。getInstance()
都创建一个新实例,那么它并不是真正的单例,只是一个静态工具方法。话虽如此,我的理解可能存在缺陷,请纠正我。 - Sanket Berde通常情况下,无需子类化 Application。在大多数情况下,静态单例可以以更模块化的方式提供相同的功能。如果您的单例需要全局上下文(例如注册广播接收器),则可以给检索它的函数传递一个 Context,该函数在首次构建单例时内部使用 Context.getApplicationContext()。
我也遇到了同样的问题:在Android中应该使用单例还是制作一个子类android.os.Application?
一开始我尝试使用Singleton,但是我的应用程序在某个时刻需要调用浏览器。
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
问题是如果手机内存不足,大多数类(即使是单例)都会被清除以获得一些内存,因此当从浏览器返回我的应用程序时,它每次都会崩溃。
解决方法:将所需数据放在Application类的子类中。
Application和Singleton不同的原因在于:
来自权威消息…
在开发应用程序时,您可能需要在整个应用程序中全局共享数据、上下文或服务。例如,如果您的应用程序具有会话数据,如当前已登录的用户,则可能希望公开此信息。在Android中,解决此问题的模式是使android.app.Application实例拥有所有全局数据,然后将您的Application实例视为一个单例,并使用静态访问器访问各种数据和服务。
编写Android应用程序时,您保证只有一个android.app.Application类的实例,因此(并且这也是Google Android团队推荐的),可以将其视为单例。也就是说,您可以安全地向Application实现添加一个静态getInstance()方法。如下所示:
public class AndroidApplication extends Application {
private static AndroidApplication sInstance;
public static AndroidApplication getInstance(){
return sInstance;
}
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
}
它们实际上是相同的。 我能看到一个区别。使用Application类,您可以在Application.onCreate()中初始化变量,并在Application.onTerminate()中销毁它们。而使用单例模式,您必须依赖VM初始化和销毁静态变量。
我的建议:
我注意到当我的活动被销毁时,一些单例/静态字段会被重置。我在某些低端2.3设备上注意到了这一点。
我的情况非常简单:我只有一个私有字段“init_done”和一个静态方法“init”,我从activity.onCreate()中调用它。我注意到,在某些重新创建活动的情况下,方法init会重新执行。
虽然我无法证明我的说法,但这可能与单例/类何时首次创建/使用有关。当活动被销毁/回收时,似乎所有仅由此活动引用的类也会被回收。
我将单例实例移动到Application的子类中。我从应用程序实例访问它们。自那以后,我没有再注意到这个问题。
希望这可以帮助某些人。
我的活动调用了finish()方法(这并不会立即结束它,但最终会结束),然后调用Google街景视图。当我在Eclipse上进行调试时,当调用Street Viewer时,我的应用程序连接断开,我理解为整个应用程序被关闭,以释放内存(因为单个活动的结束不应该导致此行为)。尽管如此,我能够通过onSaveInstanceState()方法将状态保存在Bundle中,并在堆栈中下一个活动的onCreate()方法中恢复它。无论是使用静态单例还是子类化Application,我都面临着应用程序关闭和状态丢失的问题(除非我将其保存在Bundle中)。因此,从我的经验来看,它们在状态保留方面是相同的。我注意到在Android 4.1.2和4.2.2中会丢失连接,但在4.0.7或3.2.4中不会,这表明在某个时候内存恢复机制发生了变化。