Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Pass Application Context within Singleton and SharedPreferences Classes

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?

like image 783
user2011302 Avatar asked Jan 11 '23 22:01

user2011302


2 Answers

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

like image 184
Guillermo Merino Avatar answered Jan 22 '23 10:01

Guillermo Merino


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.

like image 27
Tadej Avatar answered Jan 22 '23 12:01

Tadej