关于java:Android中的单身人士与应用程序上下文?

Singletons vs. Application Context in Android?

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

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

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

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

  • 同步
  • 可重用性
  • 测试

我非常不同意黛安娜·哈克伯恩的回答。我们一点一点地从我们的项目中删除所有的单例,以支持轻量级的、任务范围的对象,这些对象可以在您实际需要时轻松地重新创建。

单例测试对于测试来说是一场噩梦,如果懒惰地初始化,将引入带有细微副作用的"状态不确定性"(当将调用从一个作用域移动到另一个作用域时,可能会突然出现这种情况)。可视性是另一个问题,由于单例意味着对共享状态的"全局"(=random)访问,因此在并发应用程序中不正确同步时可能会出现细微的错误。

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

回到你的问题:

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


我非常推荐单件的。如果您有一个需要上下文的singleton,请具有:

1
2
3
4
5
MySingleton.getInstance(Context c) {
    //
    // ... needing to create ...
    sInstance = new MySingleton(c.getApplicationContext());
}

与应用程序相比,我更喜欢单例应用程序,因为它有助于使应用程序更具组织性和模块化——而不是让应用程序中的所有全局状态都需要维护在一个地方,每个单独的部分都可以自行处理。另外,单例初始化(根据请求)而不是在application.oncreate()中提前执行所有初始化的过程中,这一点也很好。

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

同样,对于简单的应用程序,多线程处理不会成为单线程的问题,因为根据设计,对应用程序的所有标准回调都在进程的主线程上调度,所以除非通过线程或通过将内容提供程序或服务IBinder隐式地发布到其他过程。

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


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

There is normally no need to subclass Application. In most situation,
static singletons can provide the same functionality in a more modular
way. If your singleton needs a global context (for example to register
broadcast receivers), the function to retrieve it can be given a
Context which internally uses Context.getApplicationContext() when
first constructing the singleton.


我也有同样的问题:单件还是制作一个子类android.os.application?

首先,我尝试了单件,但我的应用程序在某个时候调用了浏览器。

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

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

解决方案:将所需数据放入应用程序类的子类中。


应用程序与singleton不同。原因如下:

  • 在UI线程中调用应用程序的方法(如onCreate);
  • 可以在任何线程中调用singleton方法;
  • 在应用程序的"onCreate"方法中,可以实例化处理程序;
  • 如果在none-ui线程中执行singleton,则无法实例化处理程序;
  • 应用程序能够管理应用程序中的活动。它具有"RegisterActivityLifecycleCallbacks"。但单例没有能力。

  • 同时考虑两者:

    • 将单例对象作为类内的静态实例。
    • 有一个公共类(context),该类为应用程序中的所有singleton对象返回singleton实例,其优点是context中的方法名将有意义,例如:context.getLoggedinuser()而不是user.getInstance()。

    此外,我建议您扩展您的上下文,不仅包括对singleton对象的访问,还包括一些需要全局访问的功能,例如:context.logoffuser()、context.readsaveddata(),等等。那么将上下文重命名为facade可能是有意义的。


    它们实际上是一样的。我能看到一个区别。通过应用程序类,您可以在application.oncreate()中初始化变量,并在application.onterminate()中销毁它们。对于singleton,您必须依赖VM初始化和销毁静态。


    从传说中的马嘴里…

    在开发应用程序时,您可能会发现有必要在整个应用程序中共享数据、上下文或服务。例如,如果您的应用程序具有会话数据,例如当前登录的用户,则您可能希望公开此信息。在android中,解决这个问题的模式是让android.app.application实例拥有所有的全局数据,然后将您的应用程序实例视为具有对各种数据和服务的静态访问器的单一实例。

    在编写Android应用程序时,保证只有一个android.app.application类的实例,因此将其视为单例是安全的(并由Google Android团队推荐)。也就是说,可以将静态getInstance()方法安全地添加到应用程序实现中。像这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class AndroidApplication extends Application {

        private static AndroidApplication sInstance;

        public static AndroidApplication getInstance(){
            return sInstance;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            sInstance = this;
        }
    }

    我的2分钱:

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

    我的案例非常简单:我只有一个私有的文件"initu done"和一个静态方法"init",它是我从activity.oncreate()调用的。我注意到init方法在重新创建活动时正在重新执行自己。

    虽然我不能证明我的肯定,但它可能与创建/使用单例/类的时间有关。当活动被销毁/回收时,似乎只有此活动引用的所有类也都被回收。

    我将singleton实例移动到应用程序的子类中。我从应用程序实例中访问它们。从那时起,就再也没有注意到这个问题。

    我希望这能帮助别人。


    我的活动调用finish()(这不会使它立即完成,但最终会完成)并调用Google Street Viewer。当我在Eclipse上调试它时,当调用Street Viewer时,我与应用程序的连接就会断开,我理解这是因为(整个)应用程序正在关闭,应该是为了释放内存(因为正在完成的单个活动不应该导致这种行为)。不过,我可以通过onsaveInstanceState()将状态保存到包中,并将其恢复到堆栈中下一个活动的onCreate()方法中。通过使用静态单例或子类化应用程序,我将面对应用程序关闭和丢失的状态(除非我将其保存在一个包中)。根据我的经验,在国家保护方面,它们是一样的。我注意到Android 4.1.2和4.2.2中的连接丢失了,但在4.0.7或3.2.4中没有,据我所知,这表明内存恢复机制在某个时刻发生了变化。