1
votes

I've spent a while reading up on this and have yet to find an answer.

I have a few activities all within one app. I'd like to share some data between them that is not suitable for intents or serialized data files. I know I can use the overall Application for this purpose, but I'm not fully understanding how it works.

We'll call my overall application class "MyApplication" and the main activity "MyActivity". I would expect that once the app begins from a cold start, it first instantiates and initializes MyApplication (calling onCreate()) and then goes on to instantiate and start my activity (MyActivity) (which was marked with the intent android.intent.action.MAIN). The logs seem to bear this out.

But... if I try to set the following Activity-wide variable, it gets set to null: private final MyApplication THISAPP = (MyApplication)getApplication();

This is peculiar because the application definitely exists at this point. (Also, I can't delay setting a final variable til MyActivity.onCreate() gets called - that's disallowed ("The final field...cannot be assigned")).

Note that this works if I don't call THISAPP "final" and I assign it in onCreate(). That of course defeats the purpose of protecting a variable with "final" though, and it seems like it should be possible to do.

So, why isn't getApplication() producing a non-null value before onCreate()? Or is this some strange matter of context? (I've found a vague reference to context not being valid til after onCreate() is done, but would that apply to the parent Application's context as seen from a child Activity? I'd expect the parent to already have that set at that point.)

Edit: to emphasize, I can get this to work if I don't try to use final and if I remember to put the "." before the application name in the manifest (a mistake I made and corrected well-before this I wrote this question). It just isn't clear why getApplication() (or getApplicationContext() for that matter) aren't usable before onCreate() in a child Activity... unless "that's just how it is".

4
This may be helpful/insightful: stackoverflow.com/questions/708012/…WilHall
I've been looking at that post but it doesn't answer why this happens as I'm seeing it (in fact, it's part of how I got this working at all, but not optimally IMHO). And it's not clear how getApplicationContext() differs from getApplication() if at all... I've tried both but they simply won't work in an Activity as part of a final variable initializer.MartyMacGyver

4 Answers

3
votes

I'd like to share some data between them that is not suitable for intents or serialized data files. I know I can use the overall Application for this purpose, but I'm not fully understanding how it works.

I'd just use static data members as a cache for your persistent store, rather than fussing around with Application. Application gives you little advantage over static data members and has one big cost: there can only be one Application, whereas you can organize your static data members/singletons however you like.

I would expect that once the app begins from a cold start, it first instantiates and initializes MyApplication (calling onCreate()) and then goes on to instantiate and start my activity (MyActivity) (which was marked with the intent android.intent.action.MAIN). The logs seem to bear this out.

Correct.

But... if I try to set the following Activity-wide variable, it gets set to null: private final MyApplication THISAPP = (MyApplication)getApplication();

Of course. The activity object has not yet been initialized. You are welcome to use initializers like this for constants or things you get from static methods (e.g., Calendar.getInstance()) or other constructors (e.g., new ArrayList<Foo>()). Do not call a superclass method an expect it to work at this point, since the constructor chain has not yet been called on the object being instantiated. This is just Java, nothing particular to Android.

2
votes

Have you done it the following way?

Created a class that implements Application

public class MySuperApplication extends Application 
{ 
    public String SomeSetting; 
}

Defined which is your Application class in manifest (important!)

<application android:name=".MySuperApplication" android:icon="@drawable/icon"

and then accessed it in your activities

app = (MySuperApplication) getApplication();
app.SomeSetting = "Test";

This should work. It does in my case.

2
votes

AFAIK, You cannot declare a empty final variable and initialize it onCreate. In java it is initialized during declaring the variable or in the constructor.

THISAPP cannot be initialized to Application object during declaration because the Application doesn't exist during compile time. Because onCreate is not a constructor, you cannot declare a empty final variable and initialize it in onCreate.

2
votes

Instance variables are created when the object (in this case an Activity object) is constructed. For getApplication() to produce a valid value then the Activity object would have to have been provided enough context (little 'c') at instantiation for this to occur.

The source for getApplication() in Activity.java is just this:

/** Return the application that owns this activity. */
public final Application getApplication() {
    return mApplication;
}

Here is where it is set:

final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
        Application application, Intent intent, ActivityInfo info, CharSequence title, 
        Activity parent, String id, Object lastNonConfigurationInstance,
        Configuration config) {
    // other code
    mApplication = application;
    // other code
}

Since mApplication is not set until after attach is called, it won't be available to getApplication() on instantiation of your Activity.