【问题标题】:Android: Strange NullPointerException while using SharedPreferencesAndroid:使用 SharedPreferences 时出现奇怪的 NullPointerException
【发布时间】:2013-12-20 13:40:54
【问题描述】:

我正在尝试创建一个静态包装类来处理我的应用程序的共享首选项。我创建了一个帮助类 MyHelper,其中包含另一个类 Setting,它处理从应用程序的共享首选项设置和获取值。我想以这种方式使用辅助方法-

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

这是我的助手类。

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...
    */
}

我在preferences.getBoolean() 方法中得到NullPointerException。我假设 preferences 在静态调用该方法时为空。

通过扩展android.app.Application 获取应用程序上下文的方法是否错误?我想知道从应用程序中使用的任何服务、活动、广播接收器或助手类获取应用程序上下文的最佳方法是什么。

我查看了 Android 开发人员的参考资料和其他几个问题,但没有一个能解决这个问题。对此问题的任何指导、建议或确切的解决方案将不胜感激。

更新:LOGCAT 错误

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

这是我的清单

<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>

【问题讨论】:

  • 首选项是null!
  • 我已经更新了问题(添加了 logcat 错误)。
  • 首选项为空!!!您应该将 AndroidManifest.xml 中的 App 替换为您的设置。像这样:
  • 我已经初始化了首选项字段:preferences = PreferenceManager .getDefaultSharedPreferences(currentContext);
  • @easton 我的应用程序中有几个类。这真的有用吗?

标签: android nullpointerexception sharedpreferences


【解决方案1】:

检查您的应用程序清单文件,您在应用程序标记中使用应用程序类名称或不建议不要将您的自定义应用程序类作为其他类的内部类

【讨论】:

    【解决方案2】:
    MyHelper.Setting.saveBoolean("auto_start", true);
    MyHelper.Setting.grabBoolean("auto_start");
    

    以下方法的key应该是“auto_start”,如果不是,则会引发空指针异常

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

    以下是我在我的应用中运行的示例

    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, "");
        }
    

    【讨论】:

    • 我无法完全理解您的意思。你能详细说明一下吗? :)
    • preferences.getBoolean("auto_start",false);
    • 这种方法有效,我同意;我不想将上下文传递给辅助类,并希望从辅助类本身获取它。这正是错误开始出现的时候。
    【解决方案3】:

    在提出请求后执行此操作:)

    prefs.edit().commit();
    

    【讨论】:

      【解决方案4】:

      您的saveBoolean 方法错误。纠正那个。奇怪的是方法返回类型是 void 并且你从那里返回一些东西。

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

      你可以像下面这样写一个辅助方法

      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);
              }
      
          }
      

      并用作

      // To store
      MyPrefs.saveBoolean(getApplicationContext(), "my_bool", true); 
      // To read
      MyPrefs.getBoolean(getApplicationContext(), "my_bool"); 
      

      【讨论】:

      • 其实错误在getBoolean()中,我只是在提问的时候加了一个伪方法saveBoolean()。
      • @NjSubedi 查看更新的答案。您使用的方式不正确。请参阅给定的示例。
      • 我不想将上下文传递给辅助类方法。有没有办法从MyHelper.Setting 类中获取应用程序的上下文?
      • 您可以使用辅助类的构造函数传递上下文,但您的方法将不是静态的。所以,没有其他方法可以将上下文获取到非 android 组件类中。
      • 还有另一种方法可以做到这一点。创建一个 Application 类并将 prefs 方法移入其中。就像您在做Setting 一样。但是这里这一定不是子类。这将始终是一个单独的类。然后您需要在清单&lt;application android:name="com.myname.Settings" 中添加一个条目。阅读更多stackoverflow.com/questions/4572338/…
      【解决方案5】:

      检查 AndroidManifest.xml 文件中的应用程序标记。您应该在 android:name 属性中正确定义类名。

      【讨论】:

      • 我不确定我该怎么做。你能帮忙吗?
      • 但是如果你把 MyHelper 类作为你的应用程序会更好。并将其作为上下文传递给 Setting 类。
      • 我在 MyHelper 中扩展了 android.app.Application 类,然后在我的清单中添加了 np.com.njs.statusinformer.MyHelper 作为 android:name。现在我想知道如何从 Setting 类中获取 MyHelper 的上下文!
      • 您可以完全删除设置类。将这些保存 /grab 方法移至 MyHelper 类。并使用 getApplication() 方法从任何 Activity 获取 MyHelper 实例。 ((MyHelper)getApplication()).saveBoolean("auto_start", true); ((MyHelper)getApplication()).grabBoolean("auto_start");
      【解决方案6】:

      您的偏好为空,因为您使用的是 MyHelper 类对象来初始化它,它不是 Activity。您必须提供 Activity 实例来初始化您的 Preference。并且放入值后,使用commit()完成保存操作。

      【讨论】:

      • 包装类MyHelper是否需要是活动类?如何获取当前上下文以作为参数提供给 PreferenceManager.getDefaultSharedPreferences()
      • 您可以通过创建 MyHelper 类的构造函数将 Activity 类的上下文传递给 MyHelper 类。
      【解决方案7】:

      通过清除所有 shared_prefs(清除应用程序数据)解决了该问题。该问题是由数据类型的差异引起的,例如。我正在将字符串作为布尔值访问。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-11
        • 1970-01-01
        • 2017-10-23
        • 1970-01-01
        相关资源
        最近更新 更多