64

In my app there's a static variable that's being set to null when I return to my app from the external browser. Seems like the app or some portion of it is killed if the external web page I'm launching is complex enough.

If the app were to be killed entirely and then relauched from the main activity that would be ok, but the relaunch is from the activity that started the browser - and it's not meant to set the app state so it's crashing when accessing the null static variable. This is a one-out-of-six device problem for me so I need some advice.

Is there a flag to set to prevent this behavior?

jchristof
  • 2,794
  • 7
  • 32
  • 47
  • "If the app were to be killed entirely and then relauched from the main activity that would be ok..." - In that case just create a class which extends `Application` and hold the static variable there. – Squonk Mar 02 '12 at 23:27
  • 2
    So is there a difference in scope of a static if in the Application.java or some other? – jchristof Mar 12 '12 at 17:49
  • @jchristof it's too late but Application's static field will not make a difference – oscarthecat Oct 10 '14 at 08:31

8 Answers8

47

This is standard behavior in most mobile operating systems, definitely including Android. Your app is in fact very often killed if some other application with higher priority (generally, if it's in the foreground it's higher priority) needs the resources. This is due to the nature of mobile devices having relatively limited resources.

You should save your data somewhere more durable. You might find this article on general Data Storage to be useful. This question should be relevant too: Saving Android Activity state using Save Instance State

Note that this is in fact not a one-out-of-six device problem. This is a "problem" on all devices, it's just more apparent on one of your devices probably because it has less memory. If you run a very memory-intensive app on any of your other devices you should see the same behavior. Also there is no flag to prevent this. This is standard and expected.

Community
  • 1
  • 1
kabuko
  • 36,028
  • 10
  • 80
  • 93
  • Ok then, is this statement true in all cases: "All activities in an app's manifest must be capable of being the launch activity to start the app." – jchristof Mar 06 '12 at 21:34
  • 1
    Nope. If your app is killed while in the background on Activity B while Activity A is the main launch activity in your app, then Activity A will be launched when you restart the app. You might also find [this doc](http://developer.android.com/reference/android/app/Activity.html#ProcessLifecycle) informative. – kabuko Mar 06 '12 at 22:23
  • I'm confused on this point because all of these happen in this case: Activity B starts the native browser. Back from browser onCreate() of activity B (not onResume()). The static variable is null that was valid up until the point of launching the browser. – jchristof Mar 12 '12 at 17:50
  • 11
    @kabuko Actually i've noticed with my Nexus S, that ever since upgrading to ICS, it seems to handle activity life cycles differently. If you leave an app while in Activity B (by pressing Home), and then return to it even days later it won't launch in Activity A; instead it will relaunch in B. This never occurred in Gingerbread (it would launch in A as you say). I've even check my Nexus One (running Gingerbread) and the application relaunches in Activity A, as we originally thought it would after the Android system kills a process. This leads me to think something in ICS changed? – Tony Chan May 12 '12 at 01:14
24

Usually this happens when the device goes to sleep mode.

This behavior of the device can be emulated by the following steps:

  1. Run the app and press the Home button
  2. In Android Studio in the lower left corner, select debugged the application and press the X button (terminate application) to the left of the application name. (Don't know how to Eclipse, but I think similarly)
  3. Click on the application icon on the device.

If the Task were activity, the app will open on the last activity and (most likely) will generate an error, because all static variables have been leaved.

  • 1
    This is useful reproduce steps. Now the debugged the application is categorized to the tab **Android Monitor**. – Shu Zhang Mar 29 '17 at 04:20
  • 1
    How about non-static variables? – ghchoi Oct 03 '17 at 01:47
  • 1
    It got updated again. in the new Android studio. Now you go to LogCat (cmd+6) On the bottom left after the screen record button there is a red square(Terminate app). You might need to expand the LogCat window to make it visible – hushed_voice Aug 03 '20 at 05:19
7

No... you should not store data in static variables on android. If you insist on doing it you will need to be able to recover from it when it is null.. you should save your state with bundles or other means.

Manfred Moser
  • 29,539
  • 13
  • 92
  • 123
6

The solution to using static's (singleton's) in Android is very easy:

Implement a class that extends android.app.Application and do all your singleton initialization within onCreate()

Reasoning:

  • the class that extends Application is executed first, even when your app's process is killed due to a low Memory condition
  • your app has context as soon as Application.onCreate() is called
Someone Somewhere
  • 23,475
  • 11
  • 118
  • 166
  • 1
    the class that extends Application is *executed * first ?? What does execute mean ? Moreover - can you provide docs for this claim ? – Mr_and_Mrs_D Nov 08 '13 at 17:49
1

Use application class for such things. It's always instantiated before any component (activities, services, receivers) of your app are going to start. So you are sure all of static variables are there and initialized.

Ali
  • 21,572
  • 15
  • 83
  • 95
1

You have to save your values in onSaveInstanceState and get it back in onRestoreInstanceState because when an activity go to stopped state lifecycle all static values will be null.

eg:

        /* save my satatic hashmap in case of activity stopped to retrieve it again in  onRestoreInstanceState method*/
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);

    //Common.PERMISION_MAP static hashmap 
            if (Common.PERMISION_MAP != null) {
                Iterator<Permission> iterator = Common.PERMISION_MAP.values()
                        .iterator();
                ArrayList<Permission> permissionList = new ArrayList<Permission>();
                while (iterator.hasNext()) {
                    Permission permission = (Permission) iterator.next();
                    permissionList.add(permission);

                }
                outState.putParcelableArrayList("PERMISSION_LIST", permissionList);
            }


        }

        /* restore my satatic hashmap when activity stopped */
        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);

            try {
                ArrayList<Permission> permissionList = savedInstanceState
                        .getParcelableArrayList("PERMISSION_LIST");

                if (Common.PERMISION_MAP == null)
                    Common.PERMISION_MAP = new HashMap<Permission, Permission>();
for (Permission permission : permissionList) {
                Common.PERMISION_MAP.put(permission, permission);

            }   
                } catch (Exception ex) {
                String string = ex != null ? ex.getMessage() : "";
                Log.e(TAG, (string != null ? string : ""));
                ex.printStackTrace();

            }
        }
0

Whenever you left your app & switching browser your app got in background. So you need to follow these steps

  1. First initialize your static variable in Sharedpreferece or in savedInstanceState as follow

    sharedpreference.purString("your_static_variable_name","your_static_variable_value").
    

    or

    savedInstanceState.putString("your_static_variable_name","your_static_variable_value").
    

in the first execution of oncreate() method of activity or elsewhere

  1. Second, reinitialize your static variables in onResume() methods via sharedpreference or savedInstance whichever is used earlier.
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
0

You probably just want to follow the second link by kabuko. But if you want to keep your static variable (perhaps you have some great reason for this), you could do this:

private static MyObjType getVariable()
{
   if (myVar == null)
     myVar = new MyObjType();  // do whatever else you need to here

   return myVar;
}

That way you can replace your calls to myVar.test() with getVariable().test() and you know it will never cause a null pointer exception.

Mark D
  • 3,317
  • 1
  • 26
  • 27