Android中的单身人士与应用程序上下文?
回顾这篇文章列举了使用单例的几个问题,并看到了几个Android应用程序使用单例模式的例子,我不知道是否是一个好主意,而不是通过全局应用程序状态共享单个实例(subclassing android.os.Application并获得它通过context.getApplication())。
这两种机制有什么优点/缺点?
说实话,我希望在这篇文章中有同样的答案与Web应用程序的单例模式,不是一个好主意! 但适用于Android。 我对么? DalvikVM有什么不同呢?
编辑:我想对涉及的几个方面有意见:
- 同步
- 可重用性
- testing
我非常不同意Dianne Hackborn的回应。 我们一点一点地从我们的项目中删除所有的单身人士,以支持轻量级的,任务范围的对象,当您真正需要时,可以很容易地重新创build这些对象。
单身是testing的噩梦,如果懒惰地初始化,会引入带有微妙副作用的“状态不确定性”(当从一个范围向另一个范围移动对getInstance()的调用时可能突然出现)。 可视性已被提及为另一个问题,由于单身意味着“全局”(随机)访问共享状态,所以在并发应用程序中没有正确同步时可能会出现细微的错误。
我认为这是一个反模式,这是一个糟糕的面向对象的风格,基本上等同于维护全局状态。
回到你的问题:尽pipe应用程序上下文本身可以被认为是一个单例,但它是框架pipe理的,并且有一个定义良好的生命周期,范围和访问path。 因此,我相信,如果您确实需要pipe理应用程序全局状态,则应该到此处,无处不在。 对于其他任何事情,重新思考一下是否真的需要一个单例对象,或者是否可以重写单例类来实例化实现手头任务的小型短暂对象。
我非常推荐单身人士。 如果你有一个需要上下文的单身人士,请:
MySingleton.getInstance(Context c) { // // ... needing to create ... sInstance = new MySingleton(c.getApplicationContext()); }
我比单一的应用程序更喜欢它,因为它有助于保持应用程序更加有组织和模块化 – 而不是有一个地方应用程序中的所有全局状态需要维护,每个独立的部分可以自己照顾自己。 另外事实上,单身人士懒惰地初始化(在请求),而不是在Application.onCreate()中预先执行所有初始化的path是好的。
单身人士没有任何内在的错误。 只要正确使用它们,当它是有道理的。 Android框架实际上有很多,因为它保持每个进程的caching加载的资源和其他这样的东西。
同样对于简单的应用程序,multithreading并不会成为singleton的问题,因为通过devise,应用程序的所有标准callback都被分派到进程的主线程中,所以除非通过线程显式引入它,否则不会发生multithreading通过将内容提供者或服务IBinder发布到其他进程来隐式地进行。
只是想你在做什么。 🙂
来自: http : //developer.android.com/reference/android/app/Application.html
通常不需要子类Application。 在大多数情况下,静态单例可以以更模块化的方式提供相同的function。 如果你的单例需要一个全局上下文(例如注册广播接收者),那么检索它的函数可以被赋予一个Context,它在第一次构造单例时在内部使用Context.getApplicationContext()。
我有同样的问题:单身或build立一个子类android.os.Application?
首先我尝试了Singleton,但是我的应用程序在某个时候打电话给浏览器
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
问题是,如果手机没有足够的内存,你的大部分类(甚至是单身人士)都会被清理干净以获得一些内存,所以当从浏览器返回到我的应用时,它每次都会崩溃。
解决scheme:将所需的数据放入Application类的子类中。
应用程序与Singleton不一样,原因是:
- 应用程序的方法(如onCreate)在ui线程中调用;
- 单例的方法可以在任何线程中调用;
- 在Application的“onCreate”方法中,可以实例化Handler;
- 如果单例在非UI线程中执行,则不能实例化Handler;
- 应用程序具有pipe理应用程序中活动的生命周期的能力。它具有“注册活动生命周期callback”的方法,但是单例没有能力。
同时考虑:
- 在类中有单例对象作为静态实例。
- 具有一个通用的类(Context),它返回应用程序中所有singelton对象的单例实例,其优点是Context中的方法名将是有意义的,例如:context.getLoggedinUser()而不是User.getInstance()。
此外,我build议您扩展您的上下文不仅包括访问单例对象,但需要全局访问一些function,例如:context.logOffUser(),context.readSavedData()等可能重命名的上下文那么门面就有意义了。
他们实际上是一样的。 我可以看到一个区别。 使用Application类,您可以在Application.onCreate()中初始化您的variables并在Application.onTerminate()中销毁它们。 与单身你必须依靠虚拟机初始化和摧毁静态。
我的2美分:
我注意到当我的活动被破坏时,一些单身/静态字段被重置。 我在一些低端的2.3设备上注意到了这一点。
我的情况非常简单:我只是拥有一个私人的“init_done”和一个从activity.onCreate()调用的静态方法“init”。 我注意到init方法在重新创build活动时重新执行。
虽然我无法certificate我的肯定,但是可能与单独/单独创build/使用时相关。 当活动被破坏/回收时,似乎只有这个活动所涉及的所有类别都被回收了。
我把我的单例实例移到了一个Application类的子类中。 我从应用程序实例访问它们。 从此,再也没有注意到这个问题。
我希望这可以帮助别人。
我的活动调用完成()(这不会立即完成,但最终会),并调用Google街景浏览器。 当我在Eclipse上进行debugging时,当调用Street Viewer时,与应用程序的连接中断,我将其理解为正在closures的(整个)应用程序,应该释放内存(因为完成的单个活动不应导致此行为) 。 不过,我可以通过onSaveInstanceState()在Bundle中保存状态,并在堆栈中下一个活动的onCreate()方法中恢复它。 通过使用静态单例或子类化应用程序我面对应用程序closures和丢失状态(除非我将它保存在一个包中)。 所以从我的经验来看,他们在国家保护方面是一样的。 我注意到连接丢失在Android 4.1.2和4.2.2,但不是在4.0.7或3.2.4,据我的理解,这表明内存恢复机制已经改变了一些点。
从谚语的马嘴里
在开发应用程序时,您可能会发现需要在整个应用程序中全局共享数据,上下文或服务。 例如,如果您的应用程序具有会话数据(例如当前login的用户),则可能需要公开此信息。 在Android中,解决这个问题的模式是让你的android.app.Application实例拥有所有的全局数据,然后把你的Application实例作为一个单独的静态访问器来处理各种数据和服务。
在编写一个Android应用程序时,你只能保证只有一个android.app.Application类的实例,所以它是安全的(并且由Google Android团队推荐)将其视为一个单例。 也就是说,您可以安全地将一个静态getInstance()方法添加到您的应用程序实现中。 像这样…
public class AndroidApplication extends Application{ private static AndroidApplication sInstance; public static AndroidApplication getInstance(){ return sInstance; } @Override public static void onCreate(){ super.onCreate() sInstance = this; } }