Android Studio:键值对存储sharedPreferences
一、了解 SharedPreferences
SharedPreferences是Android的一个轻量级存储工具,它采用的存储结构是Key-Value的键值对方式,类似于Java的Properties,二者都是把Key-Value的键值对保存在配置文件中。不同的是,Properties的文件内容形如Key=Value,而SharedPreferences的存储介质是XML文件,且以XML标记保存键值对。保存共享参数键值对信息的文件路径为:/data/data/应用包名/shared prefs/文件名.xml。下面是一个共享参数的XML文件例子:
<?xml version="1.0" encoding="utf-8"?>
<map>
<string name="dark_mode">true</string>
<string name="language">en</string>
<boolean name="is_logged_in">true</boolean>
<string name="user_id">12345</string>
</map>
<map>
标签:这个标签包裹了所有存储的键值对。它表示整个存储的数据集合。
<string name="key">value</string>
:用来存储 String
类型的数据。例如,dark_mode
被存储为 "true"
(作为字符串)。
<boolean name="key">value</boolean>
:存储 boolean
类型的数据,像 is_logged_in
被存储为 true
。
SharedPreferences
不能直接存储集合或数组,但它可以通过多次写入相同的键(如下例中的 favorite_colors
)来模拟集合。每个 <string>
标签都是键为 favorite_colors
的一个值。
<?xml version="1.0" encoding="utf-8"?>
<map>
<string name="favorite_colors">blue</string>
<string name="favorite_colors">green</string>
<string name="favorite_colors">red</string>
</map>
基于XM工格式的特点,共享参数主要用于如下场合:
(1) 简单且孤立的数据。若是复杂且相互关联的数据,则要保存在关系数据库中。
(2) 文本形式的数据。若是二进制数据,则要保存至文件。
(3) 需要持久化存储的数据。App退出后再次启动时,之前保存的数据仍然有效。
二、实际存储案例
public class ShareWriteActivity extends AppCompatActivity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
private SharedPreferences mShared; // 声明一个共享参数对象
private EditText et_name; // 声明一个编辑框对象
private EditText et_age; // 声明一个编辑框对象
private EditText et_height; // 声明一个编辑框对象
private EditText et_weight; // 声明一个编辑框对象
private boolean isMarried = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_share_write);
et_name = findViewById(R.id.et_name);
et_age = findViewById(R.id.et_age);
et_height = findViewById(R.id.et_height);
et_weight = findViewById(R.id.et_weight);
CheckBox ck_married = findViewById(R.id.ck_married);
ck_married.setOnCheckedChangeListener(this);
findViewById(R.id.btn_save).setOnClickListener(this);
// 从share.xml中获取共享参数对象
mShared = getSharedPreferences("share", MODE_PRIVATE);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
isMarried = isChecked;
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_save) {
String name = et_name.getText().toString();
String age = et_age.getText().toString();
String height = et_height.getText().toString();
String weight = et_weight.getText().toString();
if (TextUtils.isEmpty(name)) {
ToastUtil.show(this, "请先填写姓名");
return;
} else if (TextUtils.isEmpty(age)) {
ToastUtil.show(this, "请先填写年龄");
return;
} else if (TextUtils.isEmpty(height)) {
ToastUtil.show(this, "请先填写身高");
return;
} else if (TextUtils.isEmpty(weight)) {
ToastUtil.show(this, "请先填写体重");
return;
}
SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
editor.putString("name", name); // 添加一个名叫name的字符串参数
editor.putInt("age", Integer.parseInt(age)); // 添加一个名叫age的整型参数
editor.putLong("height", Long.parseLong(height)); // 添加一个名叫height的长整型参数
editor.putFloat("weight", Float.parseFloat(weight)); // 添加一个名叫weight的浮点数参数
editor.putBoolean("married", isMarried); // 添加一个名叫married的布尔型参数
editor.putString("update_time", DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss"));
editor.commit(); // 提交编辑器中的修改
ToastUtil.show(this, "数据已写入共享参数");
}
}
}
活动页面对应的xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp" >
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="姓名:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="3dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@+id/tv_name"
android:background="@drawable/editext_selector"
android:gravity="left|center"
android:hint="请输入姓名"
android:inputType="text"
android:maxLength="12"
android:textColor="@color/black"
android:textSize="17sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp" >
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="年龄:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_age"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="3dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@+id/tv_age"
android:background="@drawable/editext_selector"
android:gravity="left|center"
android:hint="请输入年龄"
android:inputType="number"
android:maxLength="2"
android:textColor="@color/black"
android:textSize="17sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp" >
<TextView
android:id="@+id/tv_height"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="身高:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_height"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="3dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@+id/tv_height"
android:background="@drawable/editext_selector"
android:gravity="left|center"
android:hint="请输入身高"
android:inputType="number"
android:maxLength="3"
android:textColor="@color/black"
android:textSize="17sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp" >
<TextView
android:id="@+id/tv_weight"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="体重:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_weight"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="3dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@+id/tv_weight"
android:background="@drawable/editext_selector"
android:gravity="left|center"
android:hint="请输入体重"
android:inputType="numberDecimal"
android:maxLength="5"
android:textColor="@color/black"
android:textSize="17sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="40dp" >
<CheckBox
android:id="@+id/ck_married"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:checked="false"
android:text="已婚"
android:textColor="@color/black"
android:textSize="17sp" />
</RelativeLayout>
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存到共享参数"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
其实就是收集个人信息,并把个人信息以键值对的形式存储。
代码中需要学习的有以下几点:
mShared = getSharedPreferences("share", MODE_PRIVATE);
1.这是 Android 中用于获取 SharedPreferences
的方法,作用是获取名为 "share"
的SharedPreferences
实例,用于存储和读取应用的键值对数据。
2.由以上代码可知,getSharedPreferences方法的第一个参数是文件名,填share表示共享参数的文件名是share.xml;第二个参数是操作模式,填MODE PRIVATE表示私有模式,表示仅限当前应用访问(默认模式)
3.在 Android 中使用 getSharedPreferences("share", MODE_PRIVATE)
方法时,不需要提前手动创建一个 share.xml
文件。Android 会自动处理该文件的创建。
4.当你第一次调用 getSharedPreferences("share", MODE_PRIVATE)
时,Android 会在应用的默认存储目录中(通常是 /data/data/your.package.name/shared_prefs/
)创建一个名为 share.xml
的文件。如果该文件已经存在,它将直接打开该文件用于读取或写入数据。
代码执行流程:
-
检查是否已有
"share.xml"
文件:- 如果文件存在,则返回该
SharedPreferences
实例,并可以读取其中的数据。 - 如果文件不存在,则自动创建一个新文件(但不会立刻写入数据,只有在
apply()
或commit()
时才写入)。这个文件是存储在用户手机内的。
- 如果文件存在,则返回该
-
返回
SharedPreferences
对象:- 这个对象提供
getXXX()
方法(如getString()
、getBoolean()
),用于读取存储的数据。
- 这个对象提供
另外注意上述代码采用了commit方法提交修改,该方法会把数据直接写入磁盘。如果想要更好的性能,可将commit方法改为apply方法,该方法的提交操作会先将数据写入内存,然后异步把数据写入磁盘。
三、效果展示
点击保存,所有数据会以commit的方式提交写入手机磁盘。
四、读取数据
@SuppressLint("DefaultLocale")
public class ShareReadActivity extends AppCompatActivity {
private TextView tv_share; // 声明一个文本视图对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_share_read);
tv_share = findViewById(R.id.tv_share);
readSharedPreferences(); // 从共享参数中读取信息
}
// 从共享参数中读取信息
private void readSharedPreferences() {
// 从share.xml中获取共享参数对象
SharedPreferences shared = getSharedPreferences("share", MODE_PRIVATE);
String desc = "共享参数中保存的信息如下:";
// 获取共享参数保存的所有映射配对信息
Map<String, Object> mapParam = (Map<String, Object>) shared.getAll();
// 遍历该映射对象,并将配对信息形成描述文字
for (Map.Entry<String, Object> item_map : mapParam.entrySet()) {
String key = item_map.getKey(); // 获取该配对的键信息
Object value = item_map.getValue(); // 获取该配对的值信息
if (value instanceof String) { // 如果配对值的类型为字符串
desc = String.format("%s\n %s的取值为%s", desc, key,
shared.getString(key, ""));
} else if (value instanceof Integer) { // 如果配对值的类型为整型数
desc = String.format("%s\n %s的取值为%d", desc, key,
shared.getInt(key, 0));
} else if (value instanceof Float) { // 如果配对值的类型为浮点数
desc = String.format("%s\n %s的取值为%f", desc, key,
shared.getFloat(key, 0.0f));
} else if (value instanceof Boolean) { // 如果配对值的类型为布尔值
desc = String.format("%s\n %s的取值为%b", desc, key,
shared.getBoolean(key, false));
} else if (value instanceof Long) { // 如果配对值的类型为长整型
desc = String.format("%s\n %s的取值为%d", desc, key,
shared.getLong(key, 0L));
} else { // 如果配对值的类型为未知类型
desc = String.format("%s\n参数%s的取值为未知类型", desc, key);
}
}
if (mapParam.size() <= 0) {
desc = "共享参数中保存的信息为空";
}
tv_share.setText(desc);
}
}
重点是下面的代码,从共享对象中获取所有配置信息。
Map<String, Object> mapParam = (Map<String, Object>) shared.getAll();
运行之后可以得到