单例与Android中的应用程序上下文?

问题

回顾一下这个post enumerating several problems of using singletons并且看过几个使用单例模式的Android应用程序的例子,我想知道使用Singletons而不是通过全局应用程序状态共享的单个实例(子类化android.os.Application并通过context.getApplication()获取它)是一个好主意。

两种机制都有哪些优点/缺点?

说实话,我希望在这篇文章Singleton pattern with Web application, Not a good idea!中得到相同的答案,但是应用于Android。我对么? DalvikVM有什么不同呢?

编辑:我想就所涉及的几个方面提出意见:

  • 同步
  • 可重用性
  • 测试

#1 热门回答(286 赞)

我非常不同意Dianne Hackborn的回应。我们一点一点地从项目中删除所有单例,转而使用轻量级的任务范围对象,这些对象很容易在你真正需要时重新创建。

单例是一个测试的噩梦,如果懒洋洋地进行初始化,将引入53596952"状态不确定性",带来微妙的副作用(当从一个范围移动到另一个范围的getInstance()时可能突然出现)。可见性已被提及为另一个问题,并且由于单例隐含"全局"(=随机)**访问共享状态,因此在并发应用程序中未正确同步时可能会出现细微错误。

我认为它是一种反模式,它是一种糟糕的面向对象的风格,基本上相当于维持全球状态。

回到你的问题:

尽管应用程序上下文本身可以被视为单例,但它是由框架管理的,并且具有明确定义的生命周期,范围和访问路径。因此,我相信如果你确实需要管理应用程序全局状态,它应该在这里,其他地方。对于其他任何事情,重新考虑如果你需要一个单独的对象,或者是否也可以重写你的单例类而不是实例化执行手头任务的小的,短期的对象。


#2 热门回答(220 赞)

我非常推荐单例。如果你有需要上下文的单例,请:

MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

我更喜欢单例而不是应用程序,因为它有助于保持应用程序更有条理和模块化 - 而不是让一个地方需要维护整个应用程序中的所有全局状态,每个单独的部分都可以自行处理。事实上,单例懒惰地初始化(在请求时)而不是引导你在Application.onCreate()中预先做所有初始化的道路是好的。

使用单例并没有什么本质上的错误。只要有意义,请正确使用它们。 Android框架实际上有很多,因为它可以维护已加载资源和其他此类事物的每个进程缓存。

同样对于简单的应用程序,多线程不会成为单例的问题,因为通过设计,应用程序的所有标准回调都会在进程的主线程上调度,因此除非你通过线程或明确地引入多线程,否则不会发生多线程隐式地通过将内容提供者或服务IBinder发布到其他进程。

只要考虑一下你在做什么。 :)


#3 热门回答(18 赞)

来源:Developer > reference - Application

通常不需要子类Application。在大多数情况下,静态单例可以以更模块化的方式提供相同的功能。如果你的单例需要一个全局上下文(例如注册广播接收器),那么检索它的函数可以给一个Context,它在第一次构造单例时在内部使用Context.getApplicationContext()。