当应用程序被强制关闭或设备重新启动时,共享首选项会重置数据

11

我正在开发一个应用程序,其中我正在使用SharedPreferences存储usernamepassword。一切都很好,我可以成功地存储和检索值。但是当我重新启动设备或强制关闭应用程序时,存储在SharedPreferences中的值将被重置。当我再次启动我的应用程序时,SharedPreferences键中的值变为null。这里是我存储值的代码:

SharedPreferences emailLoginSP;

emailLoginSP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
emailLoginSP.edit().putString("prefEmailId", email_text).commit();
emailLoginSP.edit().putString("prefUserId", userIDToken).commit();
emailLoginSP.edit().putString("prefAccess_token", accessToken).commit();

Intent i = new Intent(LoginWithEmail.this,UserInfoActivity.class);
i.putExtra("acess_token", accessToken);
i.putExtra("user_id", userIDToken);
i.putExtra("emailID", email_text);
startActivity(i);

而这就是我如何检索它:

SharedPreferences emailLoginSP = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());

loginEmail = emailLoginSP.getString("prefEmailId", null);
loginUserId = emailLoginSP.getString("prefUserId", null);
loginAccessToken = emailLoginSP.getString("prefAccess_token", null);

到目前为止一切都正常运行。 我再次说明我的问题是当我强制关闭或重启设备时,我会得到空值。我们能把它永久存储在应用程序内存中吗?还是我这里做错了什么?

任何帮助都将不胜感激。


当您在SP中存储值后重新启动设备时,它不会返回NULL,看起来您可能有其他问题。您能告诉我们您在哪里遇到了强制关闭吗? - RobinHood
我没有遇到强制关闭的问题。我已经通过设置->应用程序强制停止了该应用,并从那里强制停止了它。当我这样做时,无论是重新启动手机还是强制停止它,我的值都会变成null。 - Anupam
@Anupam,我下面的解决方案将保留“强制停止”中的值,当您重新启动设备等时。SharedPreferences将值存储到XML中,因此无论应用程序如何被销毁,它们始终会被保留。https://dev59.com/im025IYBdhLWcg3wNTEV 您使用的存储或检索代码肯定有问题。 - wired00
原来这也可能是由于无效的首选项键引起的,例如包含换行符的键:https://dev59.com/54fca4cB1Zd3GeqPlqU6 - caw
仅凭您的代码看来,似乎您错过了editor.commit(),因为它会将值放回到共享首选项中。这在Android文档中有提到。SharedPreferences对象修改值所使用的接口。您在编辑器中所做的所有更改都是批处理的,并且只有在调用commit()或apply()之后才会复制回原始SharedPreferences中。链接:https://developer.android.com/reference/android/content/SharedPreferences.Editor#apply() - skarfa
6个回答

10

我有一个登录界面,希望在应用程序关闭/销毁/电话等情况下,在内部屏幕上仍然保持“已登录”的状态。

我有一个首选项对象来保存登录注册后的值。 我在所有关键屏幕的onResume()方法中读取首选项值。

例如,在登录之后:

SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(activity);
SharedPreferences.Editor editor = app_preferences.edit();
editor.putString("sessionId", application.currentSessionId);
editor.putString("userId", application.currentUserId);
editor.putString("userEmail", application.currentUserEmail);
editor.putString("siteUserId", application.currentSiteUserId);
editor.commit();

在Activity的onResume()方法中: (即在内部屏幕中)

SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(activity);
application.currentSessionId = app_preferences.getString("sessionId", "");
application.currentUserId = app_preferences.getString("userId", "");
application.currentUserEmail = app_preferences.getString("userEmail", "");
application.currentSiteUserId = app_preferences.getString("siteUserId", "");
注意。我有应用程序“全局”变量,即application.currentSessionId,你可以只替换你的变量。
也许尝试类似的东西,因为你可能没有正确保存或检索值,因为SharePreferences应该有效。

3
为了未来的读者,SharedPreferences.Editor 使用建造者模式构建提交事务。editor.putString(k,v).putLong(k2,n).commit(); 在 commit() 之后,您应该使用一个新的 Editor 或在重用前调用 editor.clear()。 - CodeShane
我遇到了同样的问题。我的代码与你上面提到的一样,唯一的区别是 u = URLDecoder.decode(u,"UTF-8"); u 是用户的电子邮件地址。因为这段代码,我会遇到同样的问题吗? - Mohini

8

你好!

解决方案1 解决方案2

解决方案1:

  SharedPreferences sharedPreferences = getSharedPreferences("namefile",               
    Context.MODE_PRIVATE);//store or retrieved file "namefile.xml".
    /*or 
   SharedPreferences sharedPreferences    
   =getActivity().getSharedPreferences("namefile", Context.MODE_PRIVATE); 
   (use Shared Preferences in Fragment)*/
   String getValueFromKey = sharedPreferences.getString("yourKey",new   
   String());
   //Log.d("printf:",getValueFromKey );
   getValueFromKey ="Hahaha"; /*  Edit value    
   or Do nothing …… */
   SharedPreferences.Editor editor = sharedPreferences.edit();
   editor.clear(); //[important] Clearing your editor before using it.
   editor.putString("yourKey", getValueFromKey);
   editor.commit();
解决方案2:
SharedPreferences sharedPreferences = getSharedPreferences("namefile",     
  Context.MODE_PRIVATE);//store or retrieved file "namefile.xml".
/*or 
SharedPreferences sharedPreferences = 
getActivity().getSharedPreferences("namefile", Context.MODE_PRIVATE); 
(use Shared Preferences in Fragment)
*/
Set<String> getListValueFromKey =
sharedPreferences.getStringSet("yourKey",new HashSet<String>());
getListValueFromKey.add("Hahaha");
getListValueFromKey.add("Kakaka");
getListValueFromKey.add("Hohoho");
/*  Add value or Do nothing …… */
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear(); //[important] Clearing your editor before using it.
editor.putStringSet("yourKey", getListValueFromKey);
editor.commit();
我曾经遇到与你完全相同的问题,这个方法对我很有用。如果需要查看我的全部代码示例,请参考:

1
方案2中的代码有问题;您不允许修改并重新保存从getStringSet获取的值。请参阅文档 - Sam

1

改为:

SharedPreferences emailLoginSP;
SharedPreferences.Editor SPEdit;

emailLoginSP = getSharedPreferences("pref_file_name",MODE_PRIVATE);
SPEdit = emailLoginSP.edit();

SPEdit.putString("prefEmailId", email_text);
SPEdit.putString("prefUserId", userIDToken);
SPEdit.putString("prefAccess_token", accessToken);
SPEdit.commit();

注意:这个代码未经测试,只是从记忆中书写,因此可能存在错误。

你需要最小化.commit()的调用次数,这就是为什么只在最后调用一次。

pref_file_name可以随意命名,使用小写字母,不能以数字开头等。


0
确保使用相同的文件进行保存和检索。 这让我看起来很蠢 :(
// When saving
public SharedPreferences.Editor getEditor(Activity activity, int mode) {
    SharedPreferences sharedPref = activity.getApplicationContext().getSharedPreferences(PreferenceConstants.SWAGGER_USER_PREFS, mode);
    SharedPreferences.Editor editor = sharedPref.edit();
    return editor;
}


// When getting it
    public SharedPreferences getSharedPref(Activity activity, int mode) {
            SharedPreferences sharedPref = activity.getSharedPreferences(PreferenceConstants.SWAGGER_USER_PREFS, mode);
            return sharedPref;
        }

-1

看,我已经做了如下操作。

        sharedPreferences = PreferenceManager
                .getDefaultSharedPreferences(getApplicationContext());
        editor = sharedPreferences.edit();
        isPaidVerison = sharedPreferences.getInt("isPaidVerison", 0);


        editor.putInt("isPaidVerison", 1);
        editor.commit();

这个很好用。 数据将一直保存在Sharedprefrences中,直到我们重新安装应用程序或清除数据。

我是这样检索数据的。

       isPaidVerison = sharedPreferences.getInt("isPaidVerison", 0);

-2
如果你想尝试除了共享首选项之外的其他方法,则可以使用文件来写入值,然后从中检索值。 声明一个文本文件emailLogin.txt,并按以下方式使用它来编写数据。
           try {
                Context context = MainActivity.this;
                OutputStreamWriter out=
                        new OutputStreamWriter(context.openFileOutput(EMAILLOGIN, 0));

                out.write(email_text);                   
                out.write("\r\n");
                out.write(userIDToken);                   
                out.write("\r\n");
                out.write(accessToken);                   
                out.write("\r\n");

                out.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 

在写入文件后,您可以执行以下操作来从中读取。
   File file = this.getFileStreamPath(EMAILLOGIN);

            if(file.exists())
            {
                try {
                    InputStream in=openFileInput(NUMBERS);

                    if (in!=null) {
                        InputStreamReader tmp=new InputStreamReader(in);
                        BufferedReader reader=new BufferedReader(tmp);
                        String str;
                        String strcount[]= new String[20];                                                        

                        java.util.Arrays.fill(strcount, 0, 10, "");
                        while ((str = reader.readLine()) != null) {                       
                            strcount[linecount]=str;                              
                        }

                        loginEmail = strcount[0];
                        loginUserId = strcount[1];
                        loginAccessToken = strcount[2];

                        in.close();              
                    }
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

这将确保即使您的应用程序强制关闭或设备重新启动,您仍然可以从文件中读取所需的值。


1
这不是一个好的解决方案,因为SharePreferences已经被存储到文件中了,它以XML的形式为您存储。即使像你说的那样进行“重新启动”,它也会保留值。这几乎值得投反对票。在这里阅读:https://dev59.com/im025IYBdhLWcg3wNTEV。我建议在您自己的项目user1721904中实现`SharedPreferences`,而不是重新发明轮子。希望这可以帮助你,伙计。 - wired00
1
哈哈,仅仅因为你想让自己的答案被选中,并不意味着你应该这样评论别人的答案。顺便说一下,我在我的答案开头提到了如果他想采用不同的方法可以尝试这个,而且我并没有阻止他使用SharedPreferences。 - user1721904
1
很好的BM。如果你的答案是错误的,我会告诉你。这是为了你自己好,但如果你想忽略也没关系。 - wired00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接