4

How to pass application context from Singleton class to SharedPreferences? I have a fragment and a GridView inside its onActivityCreated(Bundle savedInstanceState) method , on item-click, I am getting NullPointerException in logcat:

03-30 05:12:54.784: E/AndroidRuntime(1950): FATAL EXCEPTION: main
03-30 05:12:54.784: E/AndroidRuntime(1950): java.lang.NullPointerException
03-30 05:12:54.784: E/AndroidRuntime(1950):     at android.preference.PreferenceManager.getDefaultSharedPreferencesName(PreferenceManager.java:374)
03-30 05:12:54.784: E/AndroidRuntime(1950):     at android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:369)
03-30 05:12:54.784: E/AndroidRuntime(1950):     at com.example.duaapp.utility.SharedPreferencesSupplication.save(SharedPreferencesSupplication.java:35)

Singleton Class

public class SingletonClass {

    public static Context applicationContext;

    public static int fontSizeMin = 17;
    public static int fontSizeMax = 35;

public static final String keySelVerseFromList = "keySelVerseFromList";
    public static final String keyFavVerses = "keyFavVerses";
    public static final String keyListOfVerses = "keyListOfVerses";

    public static final String keyIsFavSelected = "keyIsFavSelected";

}

SharedPreferences

  public class SharedPreferencesSupplication {


        public void save(String valueKey, String value) {

            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
            SharedPreferences.Editor edit = prefs.edit();
            edit.putString(valueKey, value);
            edit.commit();
        }

        public void save(String valueKey, int value) {

            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
            SharedPreferences.Editor edit = prefs.edit();
            edit.putInt(valueKey, value);
            edit.commit();
        }

        public void save(String valueKey, boolean value) {

            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
            SharedPreferences.Editor edit = prefs.edit();
            edit.putBoolean(valueKey, value);
            edit.commit();
        }

        public void save(String valueKey, long value) {

            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
            SharedPreferences.Editor edit = prefs.edit();
            edit.putLong(valueKey, value);
            edit.commit();
        }
    }

On gridview_item_Click, whenever new SharedPreferencesSupplication().save(SingletonClass.keyIsFavSelected, false); is called, the app crashes and nullpointer exception is raised in logcat. Where am I going wrong?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user2011302
  • 391
  • 1
  • 4
  • 22
  • 1
    The problem is that `SingletonClass.applicationContext` is null. At least in the code posted, it is not initialized anywhere.. – Kuba Spatny Mar 30 '14 at 11:24
  • How is `SingletonClass.applicationContext` set (if set)? –  Mar 30 '14 at 11:24
  • 1
    Fix this `public static Context applicationContext;` so: `public static Context applicationContext = getApplicationContext();` – Phantômaxx Mar 30 '14 at 11:28
  • @user2011302 You need to tell us which value is null that is throwing NullPointerException. Debugger is your best friend here... – IgorGanapolsky Sep 19 '14 at 16:52

2 Answers2

6

Never use static references to Context in Android, this will cause you an important memory leak since Context has references to all the application resources.

Most of the Android UI classes have a dynamic reference to the context, in fragments you can do getActivity(), in views getContext() consider using those instead of context singletons

More information about this here

Guillermo Merino
  • 3,197
  • 2
  • 17
  • 34
  • 4
    Just to add to this: To get shared preferences you need Application Context so I would always pass it in the argument as `save(getApplicationContext(), value1, value2);` – Kuba Spatny Mar 30 '14 at 11:37
3

While Guillermo Merino concern is valid, an application Context used in a singleton class should not be automatically considered a memory leak.

Calling context.getApplicationContext() will, regardless of where or how it is accessed, always return the same instance from within your process. It will be "alive" for at least as long as the singleton will, therefore holding a reference to it should do no harm.

That said, it might not be enough to perform certain operations, as Dave Smith describes in his blog post.

Since OP is trying to access default SharedPreferences, this could be achieved using just application Context, e.g.:

// Custom Application class.
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        SingletonClass.INSTANCE.init(getApplicationContext());
    }
}

// Singleton.
public enum SingletonClass {
    INSTANCE;

    private Context applicationContext;

    public static int fontSizeMin = 17;
    public static int fontSizeMax = 35;

    public static final String keySelVerseFromList = "keySelVerseFromList";
    public static final String keyFavVerses = "keyFavVerses";
    public static final String keyListOfVerses = "keyListOfVerses";
    public static final String keyIsFavSelected = "keyIsFavSelected";

    // Make sure you only call this once - from MyApplication.
    public void init(final Context context) {
        applicationContext = context.getApplicationContext();
    }

    public Context getApplicationContext() {
        if (null == applicationContext) {
            throw new IllegalStateException("have you called init(context)?");
        }

        return applicationContext;
    }

}

I don't believe this would cause any memory leaks, but if I'm mistaken, please do correct me.

Tadej
  • 2,901
  • 1
  • 17
  • 23
  • 1
    I think you are right, it's much discussed here http://stackoverflow.com/questions/987072/using-application-context-everywhere – Kuba Spatny Mar 30 '14 at 13:35
  • @curtisLoew Why create a separate method in SingletonClass to get application context? You can just create a static method in the Application extended class - MyApplication. – IgorGanapolsky Sep 19 '14 at 16:55
  • How do you call `getApplicationContext()` from an outside class?? – IgorGanapolsky Feb 09 '16 at 19:49
  • Android studio still gives me this lint warning when hovering over INSTANCE: "Do not place Android context classes in static fields (static reference to SingletonClass which has field applicationContext pointing to Context)". Is this something I should be worried about? – user3829751 Aug 30 '16 at 17:09