11

I have an android app that is setup to start a Java activity (call it MyJavaActivity), which in turn launches a NativeActivity. When the NativeActivity finishes it returns back to MyJavaActivity.

I also have a Java singleton class (call it MyJavaSingleton) which I would like to stay in memory throughout my application's lifecycle. I set some of the singleton class's member variables from my NativeActivity (using JNI), which can later be retrieved by MyJavaActivity.

The problem is, MyJavaSingleton instance seems to be in memory until NativeActive exits, but somehow seems to be set to null again when MyJavaActivity starts up again, so all the variables I had set in NativeActivity are now reset to their defaults. Why does this happen?

 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! 
 }

In the above code extraction, "New MyJavaSIngleton instance" is printed when the app is first started, and then again right after the NativeActivity exits (ie after android_main is exited) and MyJavaActivity's onCreate is called again.

Why does MyJavaSingleton.mInstance become NULL when reentering MyJavaActivity?

8
  • 2
    why are you calling exit()? Doesn't that kill the JVM, or am I being ignorant of Android? Commented Sep 21, 2011 at 17:30
  • Yes, I don't like having to call exit() either, I feel this is a hack, but the application does not seem to return to MyJavaActivity unless I do this. Commented Sep 21, 2011 at 17:45
  • @lost_bits1110 finish() doesn't work? Commented Sep 21, 2011 at 17:46
  • As @James said you singleton should be private. Also, as written, Instance() should be synchronized. Commented Sep 21, 2011 at 17:48
  • @DeeV No, In my code snippet above you can see I call the native equivalent to '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` was showing. @Hemal I mentioned this in a previous comment - but I had originally set it to private and the behavior is the same. I have tried adding `synchronized' though still the same results :( I will update my code above to show these two changes. Commented Sep 21, 2011 at 17:54

4 Answers 4

11

Each Android app runs in its own process so as long as it keeps running, your singleton will be available. When the process dies, your singleton is lost. Therefore when the app is re-launched this singleton object will need to be re-created.

Sign up to request clarification or add additional context in comments.

2 Comments

Yes but I never quit the app entirely, the app is simply going from MyJavaActivity to NativeActivity and then back to MyJavaActivity.
I think calling the exit must be killing the process and then it restarts somehow bringing me back to MyJavaActivity. Unfortunately using exit seems to be the only way to resume back to the Java activity that called it :(
2

Be sure to read the documentation on the process lifecycle:

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

In this case, whenever your app is in the background (in terms of activities, none of your activities are visible to the user), your process can be killed at any time. If the user later returns to one of your activities, a new process will be created and a new instance of the activity created.

2 Comments

This is a good comment, however this page says 'By default, all components of the same application run in the same process'. I do not change this default mechanism, so I am assuming that NativeActivity, MyJavaActivity, and MyJavaSingleton are all part of the same process. Either MyJavaActivity and NativeActivity are always visible at some point (except when transitioning between them), so I don't know why my app's process would ever be killed or why my original singleton instance is lost and a new singleton instance is created.
If the singleton is becoming null, then either you are setting it null somewhere, or your process is going away. If you are actually never going out of the foreground, the only other way it could go away is if it crashes or uses so much memory it had to be killed.
2

"Android OS can and will terminate your singleton and not even tell you about it."

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

The author of that article suggests some solutions, such as using a Service, or subclassing the Application class. There seems to be quite a bit of support for the latter:

How to declare global variables in Android?

Comments

1

I'd make mInstance private. Just in case some other code is accidentally setting it.

4 Comments

I'm not sure who downvoted, but I had initially set it to private, and ended up setting it to public so that I could quickly print out its address values. Setting to private still causes my instance to be set to NULL at some point after exiting NativeActivity.
I hope it was because the downvoter mistakenly hit the down arrow instead of up
@lost_bits1110 I don't see how it can revert to null if it is private, unless is being set to null somewhere else in the same class. Reflection can be used to set it back to null. But in that case it would be set to null even if it is public.
Hmm I don't think I am using reflection anywhere? I also tried setting watchpoints - but Eclipse never breaks when the value is changed. I also put a finalize method in MyJavaSingleton with some print statements and a breakpoint, this never gets hit either! :S

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.