回顾这篇文章,列举了使用单例对象的几个问题 并且已经看到了几个使用单例模式的Android应用程序的例子,我想知道使用单例而不是通过全局应用程序状态共享的单个实例是否是一个好主意(子类化Android .os. application并通过context.getApplication()获取它)。

这两种机制有什么优点/缺点?

老实说,我希望在这篇文章中得到同样的答案,单例模式与Web应用程序,不是一个好主意!但应用于Android。我说的对吗?DalvikVM有什么不同?

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

同步 可重用性 测试


当前回答

它们实际上是一样的。 我能看出一点不同。使用Application类,你可以在Application. oncreate()中初始化你的变量,并在Application. onterminate()中销毁它们。对于单例,你必须依赖VM初始化和销毁静态数据。

其他回答

我的观点是:

我确实注意到,当我的活动被销毁时,一些单例/静态字段被重置。我在一些低端2.3设备上注意到了这一点。

我的案例非常简单:我只有一个私有文件“init_done”和一个静态方法“init”,我从activity.onCreate()调用。我注意到init方法在重新创建活动时重新执行了自己。

虽然我不能证明我的肯定,这可能与单例/类是什么时候第一次创建/使用有关。当活动被销毁/回收时,似乎只有这个活动引用的所有类也都被回收了。

我把我的singleton实例移动到Application的一个子类。我从应用程序实例访问它们。而且,从那以后,再也没有注意到这个问题。

我希望这能帮助到一些人。

我强烈推荐单身人士。如果你有一个需要context的单例,有:

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

比起应用程序,我更喜欢单例,因为它有助于保持应用程序更有组织性和模块化——而不是在一个地方维护整个应用程序的所有全局状态,每个单独的部分都可以照顾自己。另外,单例会延迟初始化(在请求时),而不是引导您在Application.onCreate()中预先进行所有初始化,这是很好的。

使用单例对象在本质上并没有错。只要在有意义的时候正确地使用它们。Android框架实际上有很多,用于维护加载资源的每个进程缓存和其他类似的东西。

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

对你所做的事情要深思熟虑。:)

我也有同样的问题:单例还是做一个子类android.os.Application?

首先,我尝试了单例,但我的应用程序在某些时候会调用浏览器

Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));

问题是,如果手机没有足够的内存,你的大多数类(甚至是单例)被清理以获得一些内存,当从浏览器返回到我的应用程序时,它每次都崩溃了。

解决方案:将需要的数据放在Application类的子类中。

我非常不同意Dianne Hackborn的回答。我们一点一点地从我们的项目中移除所有的单例对象,以支持轻量级的、任务范围的对象,当你真正需要它们时,它们可以很容易地重新创建。

单例是测试的噩梦,如果延迟初始化,将引入带有微妙副作用的“状态不确定性”(当将对getInstance()的调用从一个作用域移动到另一个作用域时,可能会突然出现)。可见性是另一个问题,由于单例意味着对共享状态的“全局”(=随机)访问,在并发应用程序中没有正确同步时,可能会出现微妙的错误。

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

回到你的问题:

虽然应用程序上下文本身可以被认为是一个单例,但它是由框架管理的,并且具有定义良好的生命周期、作用域和访问路径。因此,我认为如果你确实需要管理app-global状态,它应该放在这里,而不是其他地方。对于其他任何事情,重新考虑是否真的需要一个单例对象,或者是否也可以重写单例类来实例化执行手头任务的小型、短期对象。

来自:开发人员>参考-应用程序

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