【问题标题】:When/why does my Java singleton instance get destroyed?我的 Java 单例实例何时/为什么被销毁?
【发布时间】:2011-09-21 17:27:41
【问题描述】:

我有一个 android 应用程序,它设置为启动一个 Java 活动(称为 MyJavaActivity),它反过来启动一个 NativeActivity。当 NativeActivity 完成时,它会返回到 MyJavaActivity。

我还有一个 Java 单例类(称为 MyJavaSingleton),我希望在我的应用程序的整个生命周期中将其保留在内存中。我从我的 NativeActivity(使用 JNI)中设置了一些单例类的成员变量,这些变量稍后可以由 MyJavaActivity 检索。

问题是,MyJavaSingleton 实例似乎在 NativeActive 退出之前一直在内存中,但是当 MyJavaActivity 再次启动时,它似乎又被设置为 null,所以我在 NativeActivity 中设置的所有变量现在都重置为默认值。为什么会这样?

 public class MyJavaActivity extends Activity implements View.OnTouchListener
 {
   @Override
   public void onCreate(Bundle savedInstanceState) 
   {
    super.onCreate(savedInstanceState);
    MyJavaSingleton.Instance().DoStuff();
   }

   @Override
   public boolean onTouch(View arg0, MotionEvent arg1) 
   {
      Intent intent = new Intent(MyJavaActivity.this, NativeActivity.class);
      startActivity(intent); // at this point, android_main will be executed 
   }
 }

 /////////////////////////////
 public class MyJavaSingleton
 {
   static private MyJavaSingleton mInstance = null;
    synchronized public static MyJavaSingleton Instance()
{
    if( mInstance == null )
    {
        mInstance = new MyJavaSingleton();
        Log.v(TAG, "New MyJavaSIngleton instance");
    }
    return mInstance;
}
 }
 /////////////////////////////
 // Native 
 void android_main(struct android_app* state) 
 {
     // Do various stuff, set some variables on the MyJavaSingleton
     // At this point, MyJavaSingleton.mInstance is still at the same address in memory, which is good //
     ANativeActivity_finish(state->activity);
     exit(0);
     // Problem: sometime after this exit and before MyJavaActivity::onCreate is called, MyJavaSingleton.mInstance is set to null! 
 }

在上面的代码提取中,“New MyJavaSIngleton instance”在应用第一次启动时打印,然后在NativeActivity退出后(即android_main退出后)再次打印,并再次调用MyJavaActivity的onCreate。

为什么重新进入MyJavaActivity时MyJavaSingleton.mInstance变成NULL了?

【问题讨论】:

  • 你为什么要调用exit()?这不会杀死JVM,还是我对Android一无所知?
  • 是的,我也不喜欢调用 exit(),我觉得这是一个 hack,但除非我这样做,否则应用程序似乎不会返回到 MyJavaActivity。
  • @lost_bits1110 finish() 不起作用?
  • 正如@James 所说,你单身应该是私人的。另外,正如所写,Instance() 应该是 synchronized
  • @DeeV 不,在我上面的代码 sn-p 中,您可以看到我调用原生等效于 'finish(), which is ANativeActivity_finish. With only this (and no exit()), the app does not return to MyJavaActivity, it simply stops at the last screen that NativeActivity `正在显示。 @Hemal 我在之前的评论中提到了这一点 - 但我最初将其设置为 private 并且行为是相同的。我尝试添加“同步”,但结果仍然相同:(我将更新上面的代码以显示这两个更改。

标签: java android singleton android-ndk


【解决方案1】:

每个 Android 应用都在自己的进程中运行,因此只要它继续运行,您的单例就可以使用。当进程终止时,你的单例就丢失了。因此,当应用重新启动时,需要重新创建这个单例对象。

【讨论】:

  • 是的,但我从未完全退出应用程序,应用程序只是从 MyJavaActivity 转到 NativeActivity,然后再返回 MyJavaActivity。
  • 我认为调用exit 肯定会终止进程,然后它会重新启动以某种方式让我回到MyJavaActivity。不幸的是,使用 exit 似乎是恢复调用它的 Java 活动的唯一方法:(
【解决方案2】:

请务必阅读有关流程生命周期的文档:

http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html#Lifecycle

在这种情况下,只要您的应用程序处于后台(就活动而言,您的任何活动都对用户不可见),您的进程可以随时终止。如果用户稍后返回到您的某个活动,则会创建一个新流程并创建该活动的一个新实例。

【讨论】:

  • 这是一个很好的评论,但是此页面显示“默认情况下,同一应用程序的所有组件都在同一进程中运行”。我没有更改这个默认机制,所以我假设NativeActivityMyJavaActivityMyJavaSingleton 都是同一进程的一部分。 MyJavaActivityNativeActivity 在某些时候总是可见的(除非在它们之间转换时),所以我不知道为什么我的应用程序的进程会被杀死或者为什么我的原始单例实例丢失并且新的单例实例是已创建。
  • 如果单例变为空,那么您要么在某处将其设置为空,要么您的进程正在消失。如果您实际上永远不会离开前台,那么它可能消失的唯一另一种方法是如果它崩溃或使用太多内存,它必须被杀死。
【解决方案3】:

我会将 mInstance 设为私有。以防万一其他代码意外设置它。

【讨论】:

  • 我不确定谁投了反对票,但我最初将其设置为私有,最后将其设置为公开,以便我可以快速打印出它的地址值。设置为私有仍然会导致我的实例在退出 NativeActivity 后的某个时间点设置为 NULL。
  • 我希望这是因为投票者错误地点击了向下箭头而不是向上
  • @lost_bits1110 如果它是私有的,我看不出它如何恢复为 null,除非在同一类的其他地方设置为 null。反射可用于将其设置回 null。但在这种情况下,即使它是 public,它也会被设置为 null。
  • 嗯,我不认为我在任何地方都在使用反射?我也尝试设置观察点——但是当值改变时 Eclipse 永远不会中断。我还在MyJavaSingleton 中放置了一个finalize 方法,其中包含一些打印语句和一个断点,这也永远不会被命中! :S
【解决方案4】:

“Android 操作系统可以并且将会终止你的单例,甚至不会告诉你。”

来源:http://www.2linessoftware.com/2010/08/03/singletons-and-services-and-shutdowns-oh-my/

那篇文章的作者提出了一些解决方案,例如使用 Service 或子类化 Application 类。似乎对后者有相当多的支持:

How to declare global variables in Android?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-01
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多