14

Can anyone enlighten me about the safety of a class holding global values in Android?

Here's a short example of what I mean:

public class Globals {
    public static int someVariable = 0;
    public static User currentUser = null;
    public static Handler onLogin = null;
}

Then somewhere in an Activity I do the following:

Globals.someVariable = 42;
Globals.currentUser = new User("John", "Doe");

I have to rely on Globals.currentUser at multiple places in my app as soon as the user is logged in, but I'm unsure if I should do it, and also if I could use a Handler like this.

I read everywhere that an Android app could be killed anytime, does this mean it is killed completely or maybe just a part of it, thus killing my Globals class only?

Or is there any other way to store globally available data in a safe way, without writing every member change to the database (in fact, my User class is a little more complex than in this example. ;-)

Thanks for your effort!


Edit: Ok, here's what I finally did:

public class MyApp extends Application {

    private static MyApp _instance;

    public MyApp() {
        super();
        _instance = this;
    }

    public static MyApp getContext() {
        return _instance;
    }
    ....
    private User _user = null;
    public User getUser() {
        if (_user == null) _user = new User();
        return _user;
    }
}

Then modify the AndroidManifest.xml and add android:name=".MyApp" to your application node to tell the app to use your subclass.

So far everything works fine and I can easily access the current Context (f.ex. in SQLiteOpenHelper) by calling MyApp.getContext().

z00l
  • 895
  • 11
  • 21
  • possible duplicate of [Is the static safe in Android?](http://stackoverflow.com/questions/1203434/is-the-static-safe-in-android) – Ted Hopp Oct 12 '11 at 17:53
  • @z00l I don't know if your second approach is better than the first one. If it's easier for you to maintain your codebase that way, fine. But Android doesn't kill (garbage-collect) global static variables just because the application was killed (and possibly restarted with the same activity stack). Remember, Java is Java, and Android is Android. Android's management of applications is not necessarily the same as Java's memory allocation for global static variables. – IgorGanapolsky Apr 03 '13 at 16:55

2 Answers2

8

It would be better to use the Android Application class. It's meant to store global application state

http://developer.android.com/reference/android/app/Application.html

Just create a subclass and make sure to update your manifest file to use your version. Then you can store whatever you need to in it. Activities have a method getApplication() which you can cast to your class to access your implementation

Andrew Burgess
  • 5,300
  • 5
  • 30
  • 37
  • 7
    I'm not convinced that the Application class usage is is particularly necessary. On that very documented page it states, "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." – Maximus Oct 12 '11 at 17:53
  • Wow, my first question and I got a satisfying answer within two minutes... Thanks a lot, your answer really helped me out (as far as I can tell right now). – z00l Oct 12 '11 at 17:56
  • @Maximus - Very true. It's really a matter of preference I guess (the documentation first states that the class is meant to hold global state and you can supply your own implementation) – Andrew Burgess Oct 12 '11 at 18:07
  • 1
    I don't think this is safe in the way OP wants. An application's entire process can be killed off. When it is re-created, any Application instance variables will be in their initial state. See, for example the [application lifecycle video](http://developer.android.com/videos/index.html#v=fL6gSd4ugSI), particularly starting at about 4 minutes. – Ted Hopp Oct 12 '11 at 18:14
  • @TedHopp - I'm not sure how having everything in a static class or a singleton would avoid this issue – Andrew Burgess Oct 12 '11 at 18:19
  • I wasn't saying that it does, just that putting it in an Application subclass doesn't fix avoid it either. The only way to be sure the data is preserved is to either persist it somehow or save it in `onSaveInstanceState`. Another issue is that if the data has a direct or indirect reference to the activity, you've just created a huge memory leak. (So, for instance, the app won't survive very many orientation changes.) – Ted Hopp Oct 12 '11 at 18:32
  • 1
    @TedHopp - I don't think he's looking to persist the data in a static class. I think he's more looking to have the data accessible to multiple activities after loading it once (versus loading it multiple times from a datasource) – Andrew Burgess Oct 12 '11 at 18:38
  • @TedHopp I thought about persisting the User in `onSaveInstanceState` earlier, but that would imply that I do it in every `Activity` that could change the user (or subclass all those Activities), which seemed odd to me, and I didn't know if that's really necessary. But hey, I'm new to Android ;-) – z00l Oct 12 '11 at 18:42
  • 2
    @z00l - If you kept the values in a Globals class and used getters/setters instead of allowing public access, then every time a variable was set the setter could make sure it was persisted. Then when the Globals object is initialized, it could restore the persisted values. Then there would be no need to use `onSaveInstanceState`. – Ted Hopp Oct 12 '11 at 20:40
1

The pattern is discouraged--you will run into problems when unit testing.

Can you explain how you unit-test a class that must supply different custom "Users" here? You are either forcing a mock/fake class into "User" which will probably have a cross-effect on other tests or you are putting an if(test) into your code which gets ugly quick.

Over time populating this class artificially for testing gets more complex and starts to have relationships and dependencies.

More simply it makes it difficult to unit test a class in isolation.

It's one of those patterns that a given programmer either doesn't see a problem with or never uses because he's been burnt--you'll see little middle ground.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • 2
    -​1, does not answer the question. The question is "Is a Globals class holding static variables in Android safe?" – Pacerier Nov 20 '14 at 08:36
  • Extra information is good only if the question is first answered. First answer the question, then add whatever information you think is important. If you don't have an answer, post a comment not an answer, so that the **unanswered** question would gain more visibility and have a higher chance of being answered. The question **would have been answered** if you and Andrew did not post your comments using the answer box. Now we have a question unanswered for 3 years and potential answerers don't get to see them because they don't appear in http://stackoverflow.com/unanswered – Pacerier Nov 21 '14 at 01:31
  • Clearly if you look at the dates of your downvotes it's obvious they weren't from me. Indeed I could prove it by making a downvote at a particular preset time and you'll be sure that I had not downvoted it. And I understand why they downvoted you, because people (like me) doing a given search could obviously **not** use your answer at all. You're wasting the visitors' time here by answering the wrong question. And where's the redundancy you're talking about? **The question has not been answered**, Is a Globals class holding static variables in Android safe? What's the answer? Yes / No – Pacerier Mar 29 '15 at 03:47
  • 1
    I suppose the -1 on your first comment mislead me. As to the answer, the accepted answer addresses the question better than answering it would--this is why it was accepted. If someone asks "Is it better to kill myself with a gun or pills", the answer is not "Gun" or "Pills". – Bill K Apr 05 '15 at 06:29