我的Java单例实例何时/为什么会被销毁?

11
我有一个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",然后在原生活动退出后(即在 android_main 退出后)再次打印,并在重新进入 MyJavaActivity 的 onCreate 方法时。

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


2
为什么要调用exit()?那不会杀死JVM吗?还是我对Android一无所知? - duffymo
正如@James所说,你的单例应该是私有的。另外,如所写,Instance() 应该是 synchronized 的。 - Miserable Variable
@DeeV 不是的,在我的代码片段中,你可以看到我调用了本地等效于'finish()的函数,即ANativeActivity_finish。只有这个(没有exit()),应用程序不会返回到MyJavaActivity,它只会停留在NativeActivity显示的最后一个屏幕。 @Hemal 我在之前的评论中提到过这一点-但我最初将其设置为private,行为是相同的。我尝试添加synchronized`,但结果仍然相同:( 我将更新上面的代码以显示这两个更改。 - lost_bits1110
我不知道Android中类加载是如何工作的,但每个加载该类的类加载器都会有一个static实例,因为每个类加载器都会有一个类的实例。如果这种情况可能发生,您可以添加一个static {System.out.println("Loading MyJavaSingleton");} - Miserable Variable
我猜是因为类早先被卸载了。你可以在静态块中打印类加载器,看看它们是否不同。MyJavaSingleton.class.getClassLoader()。我对Android的了解不够,所以我想知道为什么MyJavaActivity.onCreate会再次被调用。应用程序重新启动了吗? - Miserable Variable
显示剩余3条评论
4个回答

11

每个 Android 应用都在自己的进程中运行,只要它保持运行状态,你的单例就会一直存在。当进程终止时,你的单例将会丢失。因此,当应用重新启动时,这个单例对象需要被重新创建。


是的,但我从未完全退出应用程序,应用程序只是从MyJavaActivity切换到NativeActivity,然后再返回到MyJavaActivity。 - lost_bits1110
我认为调用 exit 必须杀死进程,然后以某种方式重新启动,将我带回到 MyJavaActivity。不幸的是,使用 exit 似乎是恢复到调用它的 Java 活动的唯一方法 :( - lost_bits1110

2

1
这是一个很好的评论,但是这个页面说“默认情况下,同一应用程序的所有组件都在同一个进程中运行”。我没有改变这个默认机制,所以我假设NativeActivityMyJavaActivityMyJavaSingleton都是同一个进程的一部分。无论何时MyJavaActivityNativeActivity都会在某个时刻可见(除了在它们之间进行转换时),所以我不知道为什么我的应用程序进程会被杀死,或者为什么我的原始单例实例会丢失并创建一个新的单例实例。 - lost_bits1110
2
如果单例变成了null,那么要么你在某处将其设置为null,要么你的进程已经结束。如果你确实从未离开前台,它消失的唯一其他方式是它崩溃或使用了太多内存而被杀死。 - hackbod

2

1

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


我不确定是谁给我点了踩,但我最初将其设置为私有,最终将其设置为公共,以便我可以快速打印出其地址值。将其设置为私有仍会导致我的实例在退出NativeActivity后的某个时刻被设置为NULL。 - lost_bits1110
我希望这是因为点踩的人误按了下箭头而不是上箭头。 - Miserable Variable
@lost_bits1110,如果它是私有的,我不明白它怎么会恢复为null,除非在同一个类中的其他地方设置为null。可以使用反射将其设置回null。但在这种情况下,即使它是“public”,它也将被设置为null。 - Miserable Variable
哦,我不认为我在任何地方使用了反射?我还尝试设置监视点-但是当值更改时,Eclipse从未中断。我还在MyJavaSingleton中放置了一个带有一些打印语句和断点的finalize方法,但它也从未被触发! :S - lost_bits1110

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接