Matt Quiros Matt Quiros - 2 months ago 20
Android Question

Are Android Context objects serializable?

I declared a non-final static

SharedPreferences
object called
PREFS
together with the other constants in my
Constants.java
class:

public static SharedPreferences PREFS = null;


My reason for doing so is that my app is comprised of about 6 different
AsyncTasks
that keep accessing the same shared prefs file, and I didn't want to get the
SharedPreferences
and its
Editor
every time. On my app's first run, I make a call to
getSharedPreferences()
in my
MainActivity
and store it to
PREFS
so that it points to an instance before the
AsyncTask
s are fired, and therefore avoid a
NullPointerException
.

However, I kept getting
NullPointerException
s from the
AsyncTask
s anyway. All stack traces point to the line where I make a call to
Constants.PREFS
to get a value. My theory is that after some time, Android kills my app's process, so the next time the alarm for any of my
AsyncTask
s goes off, the value of
Constants.PREFS
would already be
null
.

My question is: Should I make a static variable for
Context
instead? Will its state be persisted even when Android kills off my process? I always pass a reference of
Context
to my
AsyncTask
s when the latter are instantiated so they can call on
getSystemService()
, and that never throws a
NullPointerException
. However, I don't see
Context
extending
Serializable
from the Android docs.

Answer

Use Application class to share preferences globally across the application.

public class MyApp extends Application {
    private static Context mAppContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mAppContext = getApplicationContext();
    }

    public static SharedPreferences getPreferences(){
        return mAppContext.getSharedPreferences("my_app_preferences",MODE_MULTI_PROCESS);
    }
}

Tell android you want your custom Application class, by mentioning it in the manifest:

<application android:name=".MyApp" android:label="@string/app_name" android:icon="@drawable/ic_launcher">

Now from anywhere, just call

MyApp.getPreferences().edit().putBoolean("pref1",true). . . put more stuff . .commit()

MODE_MULTI_PROCESS ensures all AsyncTask threads get synchronized access to same instance of SharedPreferences. Also, commit() is atomic, and will persist changes to the disk.

The above pattern is also handy for accessing resources from anywhere.

Update

It seems that static reference to context causes troubles with new Instant Run feature.

Hence, the context can be required as a parameter of utility method:

public static SharedPreferences getPreferences(context){
    return context.getSharedPreferences("my_app_preferences",MODE_MULTI_PROCESS);
}