目录
介绍:SharedPreferences是一个轻量型的数据存储,一般用于存储用户的用户信息如账号,密码,是Android自带的一个本地存储。
主要作用:实现记住密码和自动登录功能
存储形式:以xml文件形式存储
存储位置:/data/data/包名/shared_prefs文件下【这个可以根据File Explorer查看,这里不做说明】
操作流程:
- 创建SharedPreferences对象
- 保存数据
要点:SharedPreferences只支持Java的基本数据类型
1、创建SharedPreferences对象
private SharedPreferences sharedPreferences; /** * 参数1:文件信息存放文件 * 参数2:操作模式MODE_PRIVATE:私有模式,新内容覆盖原内容 */ sharedPreferences=getSharedPreferences("userInfo",MODE_PRIVATE);
操作模式介绍:
MODE_PRIVATE
:默认模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容MODE_WORLD_READABLE
:允许其他应用读取这个模式创建的文件。在Android N上使用该模式将抛出SecurityException异常。【这个弃用了,不要问怎么知道了,知道的时候已经是泪了】MODE_WORLD_WRITEABLE
:允许其他应用写入这个模式创建的文件。在Android N上使用该模式将抛出SecurityException异常。【这个弃用了,不要问怎么知道了,知道的时候已经是泪了】MODE_APPEND
:如果文件已经存在了,则在文件的尾部添加数据。【这个没用过】MODE_MULTI_PROCESS
:SharedPreferences加载标志,当设置了该标志,则在磁盘上的文件将会被检查是否修改了,尽管SharedPreferences实例已经在该进程中被加载了。【这个没用过,看其他博主推荐使用ContentProvider】
2、保存数据
第一步:创建一个SharedPreferences.Editor类的对象
SharedPreferences.Editor editor = sharedPreferences.edit();
第二步:通过SharedPreferences.Editor类的对象修改数据,不同的数据类型有不同的修改数据方法如,putString,putInt,putLong等方法,所有的方法都是一个参数是键的名称,第二个参数是键的值
editor.putBoolean("ISCHECK", true);
第三步:数据输入好后需要提交才能保存数据,调用方法commit()或者apply();【两者的区别】
//方法一
editor.commit();
//方法二
editor.apply();
登录成功提示页布局代码【login.xml]
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="登录成功" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
用户登录布局代码【main.xml】
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:text="账号:" android:layout_width="match_parent" android:layout_height="wrap_content"/> <EditText android:id="@+id/edit_account" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:text="密码:" android:layout_width="match_parent" android:layout_height="wrap_content"/> <EditText android:id="@+id/edit_password" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content"> <CheckBox android:text="记住密码" android:id="@+id/checkbox_rememberpass" android:layout_width="match_parent" android:layout_weight="1" android:layout_height="wrap_content"/> <CheckBox android:text="自动登录" android:id="@+id/checkbox_againlogin" android:layout_width="match_parent" android:layout_weight="1" android:layout_height="wrap_content"/> <Button android:text="登录" android:id="@+id/button_login" android:layout_width="match_parent" android:layout_weight="1" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout>
登录成功提示页Java代码【Login.java】
package com.hacker.exercise_sharedperference; import android.os.Bundle; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; public class Login extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.login); } }
用户登录Java代码【MainActivity.java】
package com.hacker.exercise_sharedperference; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; /** * 目的:初步学习SharedPreferences * 结果:实现自动登录和记住密码 */ public class MainActivity extends AppCompatActivity { //账号,密码 private EditText account,password; //记住密码和自动登录 private CheckBox rempass,agalogin; //登录 private Button button; //用户名文本,密码文本 private String userNameValue,passwordValue; //sharedPreferences,轻量型存储 private SharedPreferences sharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); /** * 参数1:文件信息存放文件 * 参数2:操作模式MODE_PRIVATE:私有模式,新内容覆盖原内容 */ sharedPreferences=getSharedPreferences("userInfo",MODE_PRIVATE); account=findViewById(R.id.edit_account); password=findViewById(R.id.edit_password); rempass=findViewById(R.id.checkbox_rememberpass); agalogin=findViewById(R.id.checkbox_againlogin); button=findViewById(R.id.button_login); //判断记住密码多选框的状态 if(sharedPreferences.getBoolean("ISCHECK", false)) { //设置默认是记录密码状态 rempass.setChecked(true); account.setText(sharedPreferences.getString("USER_NAME", "")); password.setText(sharedPreferences.getString("PASSWORD", "")); //判断自动登陆多选框状态 if(sharedPreferences.getBoolean("AUTO_ISCHECK", false)) { //设置默认是自动登录状态 agalogin.setChecked(true); //跳转界面 Intent intent = new Intent(MainActivity.this,Login.class); MainActivity.this.startActivity(intent); } } // 登录监听事件 现在默认为用户名为:lin 密码:123 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.i("步骤2","1"); userNameValue = account.getText().toString(); passwordValue = password.getText().toString(); if(userNameValue.equals("lin")&&passwordValue.equals("123")) { Toast.makeText(MainActivity.this,"登录成功", Toast.LENGTH_SHORT).show(); //登录成功和记住密码框为选中状态才保存用户信息,即rempass.isChecked()为true时候进入if语句 if(rempass.isChecked()) { //记住用户名、密码、 SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("USER_NAME", userNameValue); editor.putString("PASSWORD",passwordValue); editor.apply(); } //跳转界面 Intent intent = new Intent(MainActivity.this,Login.class); MainActivity.this.startActivity(intent); }else{ Toast.makeText(MainActivity.this,"用户名或密码错误,请重新登录", Toast.LENGTH_LONG).show(); } } }); //监听记住密码多选框按钮事件 rempass.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (rempass.isChecked()) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean("ISCHECK", true); editor.apply(); }else { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean("ISCHECK", false); editor.apply(); } } }); agalogin.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (agalogin.isChecked()) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean("AUTO_ISCHECK", true); editor.apply(); } else { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putBoolean("AUTO_ISCHECK", false); editor.apply(); } } }); } /** * 未优化时候,提示Skipped 33 frames! The application may be doing too much work on its main thread. */ }
commit()
/** * Commit your preferences changes back from this Editor to the * {@link SharedPreferences} object it is editing. This atomically * performs the requested modifications, replacing whatever is currently * in the SharedPreferences. * * <p>Note that when two editors are modifying preferences at the same * time, the last one to call commit wins. * * <p>If you don't care about the return value and you're * using this from your application's main thread, consider * using {@link #apply} instead. * * @return Returns true if the new values were successfully written * to persistent storage. */
apply()
/** * Commit your preferences changes back from this Editor to the * {@link SharedPreferences} object it is editing. This atomically * performs the requested modifications, replacing whatever is currently * in the SharedPreferences. * * <p>Note that when two editors are modifying preferences at the same * time, the last one to call apply wins. * * <p>Unlike {@link #commit}, which writes its preferences out * to persistent storage synchronously, {@link #apply} * commits its changes to the in-memory * {@link SharedPreferences} immediately but starts an * asynchronous commit to disk and you won't be notified of * any failures. If another editor on this * {@link SharedPreferences} does a regular {@link #commit} * while a {@link #apply} is still outstanding, the * {@link #commit} will block until all async commits are * completed as well as the commit itself. * * <p>As {@link SharedPreferences} instances are singletons within * a process, it's safe to replace any instance of {@link #commit} with * {@link #apply} if you were already ignoring the return value. * * <p>You don't need to worry about Android component * lifecycles and their interaction with <code>apply()</code> * writing to disk. The framework makes sure in-flight disk * writes from <code>apply()</code> complete before switching * states. * * <p class='note'>The SharedPreferences.Editor interface * isn't expected to be implemented directly. However, if you * previously did implement it and are now getting errors * about missing <code>apply()</code>, you can simply call * {@link #commit} from <code>apply()</code>. */
这上面的注释是SDK自带的对这两种的方法解释,总结一下
相同点
1、2个编辑器如果同时调用commit()方法或者apply()方法,那么最后一个调用这个方法的输入框(编辑器)将会获得值
2、2个方法都是一系列操作不可以被打断的方法,即原子操作
不同点
1、apply没有返回值,所以也就不知道是否提交成功;而commit方法会返回boolean表明修改是否提交成功
2、apply是将修改数据原子提交到内存,而后异步真正提交到硬件磁盘;而commit是同步的提交到硬件磁盘,
3、apply方法调用的情况实在状态切换的时候
Android建议
如果不需要返回值,且在主线程中调用,推荐使用apply方法。