Java Android 中的单例 vs. 应用程序上下文?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3826905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 05:33:16  来源:igfitidea点击:

Singletons vs. Application Context in Android?

javaandroiddesign-patternssingleton

提问by mschonaker

Recalling this post enumerating several problems of using singletonsand having seen several examples of Android applications using singleton pattern, I wonder if it's a good idea to use Singletons instead of single instances shared through global application state (subclassing android.os.Application and obtaining it through context.getApplication()).

回想起这篇列举了使用单例的几个问题的帖子,并看过几个使用单例模式的 Android 应用程序的例子,我想知道使用单例代替通过全局应用程序状态共享的单个实例是否是个好主意(子类化 android.os.Application 并获取它通过 context.getApplication())。

What advantages/drawbacks would both mechanisms have?

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

To be honest, I expect the same answer in this post Singleton pattern with Web application, Not a good idea!but applied to Android. Am I correct? What's different in DalvikVM otherwise?

老实说,我希望在这篇带有 Web 应用程序的单例模式的帖子中得到相同的答案,这不是一个好主意!但适用于Android。我对么?除此之外,DalvikVM 有什么不同?

EDIT: I would like to have opinions on several aspects involved:

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

  • Synchronization
  • Reusability
  • Testing
  • 同步
  • 可重用性
  • 测试

采纳答案by Matthias

I very much disagree with Dianne Hackborn's response. We are bit by bit removing all singletons from our project in favor of lightweight, task scoped objects which can easiliy be re-created when you actually need them.

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

Singletons are a nightmare for testing and, if lazily initialized, will introduce "state indeterminism"with subtle side effects (which may suddenly surface when moving calls to getInstance()from one scope to another). Visibility has been mentioned as another problem, and since singletons imply "global" (= random)access to shared state, subtle bugs may arise when not properly synchronized in concurrent applications.

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

I consider it an anti-pattern, it's a bad object-oriented style that essentially amounts to maintaining global state.

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

To come back to your question:

回到你的问题:

Although the app context can be considered a singleton itself, it is framework-managed and has a well defined life-cycle, scope, and access path. Hence I believe that if you do need to manage app-global state, it should go here, nowhere else. For anything else, rethink if you reallyneed a singleton object, or if it would also be possible to rewrite your singleton class to instead instantiate small, short-lived objects that perform the task at hand.

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

回答by Fedor

They're actually the same. There's one difference I can see. With Application class you can initialize your variables in Application.onCreate() and destroy them in Application.onTerminate(). With singleton you have to rely VM initializing and destroying statics.

他们其实是一样的。我可以看到一个不同之处。使用 Application 类,您可以在 Application.onCreate() 中初始化变量并在 Application.onTerminate() 中销毁它们。使用单例,你必须依赖 VM 初始化和破坏静态。

回答by hackbod

I very much recommend singletons. If you have a singleton that needs a context, have:

我非常推荐单身人士。如果您有一个需要上下文的单身人士,请执行以下操作:

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

I prefer singletons over Application because it helps keep an app much more organized and modular -- instead of having one place where all of your global state across the app needs to be maintained, each separate piece can take care of itself. Also the fact that singletons lazily initialize (at request) instead of leading you down the path of doing all initialization up-front in Application.onCreate() is good.

我更喜欢单例而不是应用程序,因为它有助于使应用程序更有条理和模块化——而不是在一个地方需要维护整个应用程序的所有全局状态,每个单独的部分都可以自行处理。此外,单例延迟初始化(应请求)而不是引导您在 Application.onCreate() 中预先进行所有初始化的事实也很好。

There is nothing intrinsically wrong with using singletons. Just use them correctly, when it makes sense. The Android framework actually has a lot of them, for it to maintain per-process caches of loaded resources and other such things.

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

Also for simple applications multithreading doesn't become an issue with singletons, because by design all standard callbacks to the app are dispatched on the main thread of the process so you won't have multi-threading happening unless you introduce it explicitly through threads or implicitly by publishing a content provider or service IBinder to other processes.

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

Just be thoughtful about what you are doing. :)

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

回答by JoséMi

I had the same problem: Singleton or make a subclass android.os.Application?

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

First I tried with the Singleton but my app at some point makes a call to the browser

首先,我尝试使用 Singleton,但我的应用程序有时会调用浏览器

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

and the problem is that, if the handset doesn't have enough memory, most of your classes (even Singletons) are cleaned to get some memory so, when returning from the browser to my app, it crashed everytime.

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

Solution: put needed data inside a subclass of Application class.

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

回答by adranale

Consider both at the same time:

同时考虑两者:

  • having singleton objects as static instances inside the classes.
  • having a common class (Context) that returns the singleton instances for all the singelton objects in your application, which has the advantage that the method names in Context will be meaningful for example: context.getLoggedinUser() instead of User.getInstance().
  • 将单例对象作为类内的静态实例。
  • 有一个公共类 (Context),它返回应用程序中所有单例对象的单例实例,其优点是 Context 中的方法名称将是有意义的,例如:context.getLoggedinUser() 而不是 User.getInstance()。

Furthermore, I suggest that you expand your Context to include not only access to singleton objects but some functionalities that need to be accessed globally, like for example: context.logOffUser(), context.readSavedData(), etc. Probably renaming the Context to Facade would make sense then.

此外,我建议您扩展您的 Context 以不仅包括对单例对象的访问,还包括一些需要全局访问的功能,例如:context.logOffUser()、context.readSavedData() 等。可能将 Context 重命名为Facade 就有意义了。

回答by Somatik

From: Developer > reference - Application

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

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.

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

回答by Piovezan

My activity calls finish() (which doesn't make it finish immediately, but will do eventually) and calls Google Street Viewer. When I debug it on Eclipse, my connection to the app breaks when Street Viewer is called, which I understand as the (whole) application being closed, supposedly to free up memory (as a single activity being finished shouldn't cause this behavior). Nevertheless, I'm able to save state in a Bundle via onSaveInstanceState() and restore it in the onCreate() method of the next activity in the stack. Either by using a static singleton or subclassing Application I face the application closing and losing state (unless I save it in a Bundle). So from my experience they are the same with regards to state preservation. I noticed that the connection is lost in Android 4.1.2 and 4.2.2 but not on 4.0.7 or 3.2.4, which in my understanding suggests that the memory recovery mechanism has changed at some point.

我的活动调用finish()(它不会立即完成,但最终会完成)并调用Google Street Viewer。当我在 Eclipse 上调试它时,当 Street Viewer 被调用时,我与应用程序的连接中断,我理解这是(整个)应用程序被关闭,据说是为了释放内存(因为单个活动完成不应该导致这种行为) . 不过,我可以通过 onSaveInstanceState() 将状态保存在 Bundle 中,并在堆栈中下一个活动的 onCreate() 方法中恢复它。通过使用静态单例或子类化应用程序,我将面临应用程序关闭和丢失状态(除非我将其保存在 Bundle 中)。因此,根据我的经验,它们在状态保存方面是相同的。我注意到连接在 Android 4.1.2 和 4.2.2 中丢失,但在 4.0.7 或 3.2.4 上没有,

回答by sunhang

Application is not the same as the Singleton.The reasons are:

应用和Singleton不一样,原因是:

  1. Application's method(such as onCreate) is called in the ui thread;
  2. singleton's method can be called in any thread;
  3. In the method "onCreate" of Application,you can instantiate Handler;
  4. If the singleton is executed in none-ui thread,you could not instantiate Handler;
  5. Application has the ability to manage the life cycle of the activities in the app.It has the method "registerActivityLifecycleCallbacks".But the singletons has not the ability.
  1. 应用程序的方法(如onCreate)在ui线程中调用;
  2. 单例的方法可以在任何线程中调用;
  3. 在Application的onCreate方法中,可以实例化Handler;
  4. 如果单例在非ui线程中执行,则无法实例化Handler;
  5. 应用程序有能力管理应用程序中活动的生命周期。它有方法“registerActivityLifecycleCallbacks”。但单例没有能力。

回答by Christ

My 2 cents:

我的 2 美分:

I did notice that some singleton / static fields were reseted when my activity was destroyed. I noticed this on some low end 2.3 devices.

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

My case was very simple : I just have a private filed "init_done" and a static method "init" that I called from activity.onCreate(). I notice that the method init was re-executing itself on some re-creation of the activity.

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

While I cannot prove my affirmation, It may be related to WHEN the singleton/class was created/used first. When the activity get destroyed/recycled, it seem that all class that only this activity refer are recycled too.

虽然我无法证明我的肯定,但这可能与何时首先创建/使用单例/类有关。当活动被销毁/回收时,似乎只有该活动引用的所有类也被回收。

I moved my instance of singleton to a sub class of Application. I acces them from the application instance. and, since then, did not notice the problem again.

我将我的单例实例移到了 Application 的子类中。我从应用程序实例访问它们。并且,从那以后,再没有注意到这个问题。

I hope this can help someone.

我希望这可以帮助某人。

回答by RMcGuigan

From the proverbial horse's mouth...

从众所周知的马口...

When developing your app, you may find it necessary to share data, context or services globally across your app. For example, if your app has session data, such as the currently logged-in user, you will likely want to expose this information. In Android, the pattern for solving this problem is to have your android.app.Application instance own all global data, and then treat your Application instance as a singleton with static accessors to the various data and services.

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

When writing an Android app, you're guaranteed to only have one instance of the android.app.Application class, and so it's safe (and recommended by Google Android team) to treat it as a singleton. That is, you can safely add a static getInstance() method to your Application implementation. Like so:

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

public class AndroidApplication extends Application {

    private static AndroidApplication sInstance;

    public static AndroidApplication getInstance(){
        return sInstance;
    }

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