0

I am trying to create a static wrapper class to handle shared preferences of my app. I have created a helper class MyHelper that contains another class Setting which handles setting and getting values from app's shared preferences. I want to use the helper methods in this way-

MyHelper.Setting.saveBoolean("auto_start", true);
MyHelper.Setting.grabBoolean("auto_start");

Here goes my helper class.

public class MyHelper{

    public static class Setting extends android.app.Application {
        private static Context currentContext;
        private static SharedPreferences preferences;
        private static Editor updater;

        @Override
        public void onCreate(){
            super.onCreate();
            currentContext = this;
            preferences = PreferenceManager
                .getDefaultSharedPreferences(currentContext);
            updater = preferences.edit();
        }

        public static boolean grabBoolean(String key) {
            return preferences.getBoolean(key, false);
        }
        public static void saveBoolean(String key, boolean value) {
            preferences.putBoolean(key, value).commit();
        }
    }

    /*
    *    Some other nested classes here...
    */
}

I am getting NullPointerException at preferences.getBoolean() method. I presume preferences is null at the time the method is called statically.

Is the approach of getting Application's context by extending android.app.Application wrong? I would like to know what is the best approach to get the application's context from any service, activity, broadcast receiver or helper class used in an application.

I have gone through Android developers' reference and several other questions but none of those address this issue. Any guide, suggestion or exact solution to this problem would be highly appreciated.

Update: LOGCAT ERROR

12-04 12:14:47.467: E/AndroidRuntime(514): FATAL EXCEPTION: main

12-04 12:14:47.467: E/AndroidRuntime(514): java.lang.RuntimeException: Unable to start activity ComponentInfo{np.com.njs.statusinformer/np.com.njs.statusinformer.Setup}: java.lang.NullPointerException
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.os.Handler.dispatchMessage(Handler.java:99)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.os.Looper.loop(Looper.java:123)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.ActivityThread.main(ActivityThread.java:3683)
12-04 12:14:47.467: E/AndroidRuntime(514):     at java.lang.reflect.Method.invokeNative(Native Method)
12-04 12:14:47.467: E/AndroidRuntime(514):     at java.lang.reflect.Method.invoke(Method.java:507)
12-04 12:14:47.467: E/AndroidRuntime(514):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-04 12:14:47.467: E/AndroidRuntime(514):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-04 12:14:47.467: E/AndroidRuntime(514):     at dalvik.system.NativeStart.main(Native Method)
12-04 12:14:47.467: E/AndroidRuntime(514): Caused by: java.lang.NullPointerException
12-04 12:14:47.467: E/AndroidRuntime(514):     at np.com.njs.statusinformer.InformerHelper$Setting.grabBoolean(InformerHelper.java:115)
12-04 12:14:47.467: E/AndroidRuntime(514):     at np.com.njs.statusinformer.Setup.loadPreferences(Setup.java:102)
12-04 12:14:47.467: E/AndroidRuntime(514):     at np.com.njs.statusinformer.Setup.onCreate(Setup.java:31)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
12-04 12:14:47.467: E/AndroidRuntime(514):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
12-04 12:14:47.467: E/AndroidRuntime(514):     ... 11 more

Here is my Manifest's

<application
    android:allowBackup="true"
    android:debuggable="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <receiver android:name="np.com.njs.statusinformer.BootCompleteReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            <action android:name="android.intent.action.REBOOT" />
        </intent-filter>
    </receiver>

    <service android:name=".InformerService" >
        <intent-filter>
            <action android:name="np.com.njs.statusinformer.InformerService" />
        </intent-filter>
    </service>

    <activity
        android:name="np.com.njs.statusinformer.Setup"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
Nj Subedi
  • 317
  • 4
  • 15

7 Answers7

2

Your saveBoolean method is wrong. Correct that. Strange thing is that method return type is void and you are returning something from there.

public static void saveBoolean(String key, boolean value) {
    updater.putBoolean(key, value);
     updater.commit();

}

You can write a helper method like below

public class MyPrefs {

        private static final String PREF_NAME = "My_prefs";

        public static void saveBoolean(Context mContext, String key, boolean value) {
            SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
            SharedPreferences.Editor editor = sharedPref.edit();
            editor.putBoolean(key, value); 
            editor.commit();
        }

        public static boolean getBoolean(Context mContext, String key) {
            SharedPreferences sharedPref = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
            return sharedPref.getBoolean(key, false);
        }

    }

And use as

// To store
MyPrefs.saveBoolean(getApplicationContext(), "my_bool", true); 
// To read
MyPrefs.getBoolean(getApplicationContext(), "my_bool"); 
Pankaj Kumar
  • 81,967
  • 29
  • 167
  • 186
  • Actually the error is in getBoolean(), I just added a dummy method saveBoolean() while asking the question. – Nj Subedi Dec 04 '13 at 07:16
  • @NjSubedi See updated answer. The way you are using is not correct. See the given example. – Pankaj Kumar Dec 04 '13 at 07:29
  • I don't want to pass the context to helper class methods. Isn't there any way to get application's context from `MyHelper.Setting` class? – Nj Subedi Dec 04 '13 at 07:31
  • Either you can pass context using constructor of helper class, but then your methods will not be static. So, No there is no other way to get context into non android components classes. – Pankaj Kumar Dec 04 '13 at 07:40
  • And there is another approach to do that. Create an Application class and move prefs method into that.. Like you are doing `Setting`. But here this must not a child class. This will be always a separate class. and then you need to add an entry into manifest ` – Pankaj Kumar Dec 04 '13 at 07:46
1

after put request then do this :)

prefs.edit().commit();
GrIsHu
  • 29,068
  • 10
  • 64
  • 102
Bhanu Sharma
  • 5,135
  • 2
  • 24
  • 49
0

check your application manifest file where you using app class name in application tag or not suggetion is to do not make your custom application class as internal class of some other class

Vishal Pawar
  • 4,324
  • 4
  • 28
  • 54
0
MyHelper.Setting.saveBoolean("auto_start", true);
MyHelper.Setting.grabBoolean("auto_start");

The key for the below methods should be "auto_start".If not, then it will raise null pointer exception

 public static boolean grabBoolean(String key) {
            return preferences.getBoolean(key, false);
        }
        public static void saveBoolean(String key, boolean value) {
            return preferences.putBoolean(key, value);
        }

Below is my sample in my app which is working

static final String PREF_USER_NAME="USER_NAME";
public static SharedPreferences getSharedPreferences(Context ctx) {
        return PreferenceManager.getDefaultSharedPreferences(ctx);
    }

public static void setUserName(Context ctx, String userid) {
        Editor editor = getSharedPreferences(ctx).edit();
        editor.putString(PREF_USER_NAME, userid);
        editor.commit();
    }

    public static String getUserName(Context ctx) {
        return getSharedPreferences(ctx).getString(PREF_USER_NAME, "");
    }
Venkatesh S
  • 5,466
  • 1
  • 25
  • 30
0

Check the application tag in the AndroidManifest.xml file. You should define the class name correctly in the android:name attribute.

Shashika
  • 1,151
  • 1
  • 9
  • 21
  • I'm not exactly sure how I can do that. Could you please help? – Nj Subedi Dec 04 '13 at 07:17
  • But its better if you make the MyHelper class as your application. And pass it to the Setting class as the context. – Shashika Dec 04 '13 at 07:25
  • I extended the android.app.Application class in MyHelper, then added np.com.njs.statusinformer.MyHelper as android:name in my manifest. Now I wonder how can I get MyHelper's context from Setting class! – Nj Subedi Dec 04 '13 at 07:43
  • You can remove the Setting class completely. Move those save /grab methods to the MyHelper class. And use getApplication() method to get the MyHelper instance from any Activity. ((MyHelper)getApplication()).saveBoolean("auto_start", true); ((MyHelper)getApplication()).grabBoolean("auto_start"); – Shashika Dec 04 '13 at 07:53
0

Your preference is null, because you are using the MyHelper class object to initialize it, which is not an Activity. You have to give the instance of Activity to initialize your Preference. And after putting value, use commit() to finish the save operation.

amit singh
  • 1,407
  • 2
  • 16
  • 25
  • Does the wrapper class `MyHelper` need to be an activity class? How can I get the current context to provide as a parameter to `PreferenceManager.getDefaultSharedPreferences()` ? – Nj Subedi Dec 04 '13 at 07:21
  • You can pass the context from your Activity class to MyHelper class by making constructor of MyHelper class. – amit singh Dec 04 '13 at 07:36
0

The issue was resolved by clearing all the shared_prefs (clear application data). The problem was caused by difference in data type, eg. I was accessing a string as a boolean.

Nj Subedi
  • 317
  • 4
  • 15