Android Studio 学习记录-键值对

        本文介绍Android的键值对存储方式的使用方法,包括:如何将数据保存到共享参数,如何从共享参数读取数据,如何使用共享参数实现登录页面的记住密码功能,如何使用Jetpack集成的数据仓库。

共享参数的用法

        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'standalone='yes'?>
<map>
    <string name="name"> Mr Lee </string>
    <int name="age" value="30" />
    <boolean name="married" value="true" />
    <float name="weight" value="100.0" />
</map>

        基于XML格式的特点,共享参数主要用于如下场合:

  1. 简单且孤立的数据。若是复杂且相互关联的数据,则要保存在关系数据库中。
  2. 文本形式的数据。若是二进制数据,则要保存至文件。
  3. 需要持久化存储的数据。App退出后再次启动时,之前保存的数据仍然有效。

        在实际开发中,共享参数经常存储的数据包括:App的个性化配置信息、用户使用App的行为信息、临时需要保存的片段信息等。

        共享参数对数据的存储和读取操作类似于Map,也有存储数据的put方法,以及读取数据的get方法。调用getSharedPreferences方法可以获得共享参数实例,获取代码示例如下:

//从share.xml获取共享参数实例
SharedPreferences shared = getSharedPreferences ("share", MODE_PRIVATE);

        由以上代码可知,getSharedPreferences方法的第一个参数是文件名,填share表示共享参数的文件名是share.xml;第二个参数是操作模式,填MODE_PRIVATE表示私有模式。

        往共享参数存储数据要借助于Editor类,保存数据的代码示例如下:

android.content.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(); // 提交编辑器中的修改

        注意上述代码采用了commit方法提交修改,该方法会把数据直接写入磁盘。如果想要更好的性能,可将commit方法改为apply方法,该方法的提交操作会先将数据写入内存,然后异步把数据写入磁盘。

        从共享参数读取数据相对简单,读取数据的代码示例如下:

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

实现记住密码功能

        用户退出后重新进入登录页面,App没有回忆起上次的登录密码。现在利用共享参数改造该项目,使之实现记住密码的功能。

扫描二维码关注公众号,回复: 15252696 查看本文章

        改造的内容主要有下列3处:

  1. 声明一个共享参数对象,并在onCreate中调用getSharedPreferences方法获取共享参数的实例。
  2. 登录成功时,如果用户勾选了“记住密码”复选框,就使用共享参数保存手机号码与密码。也就是在loginSuccess方法中增加以下代码:
            // 如果勾选了“记住密码”,就把手机号码和密码都保存到共享参数中
            if (isRemember) {
                SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
                editor.putString("phone", et_phone.getText().toString()); // 添加名叫phone的手机号码
                editor.putString("password", et_password.getText().toString()); // 添加名叫password的密码
                editor.commit(); // 提交编辑器中的修改
            }
  3. 再次打开登录页面时,App从共享参数中读取手机号码与密码,并自动填入编辑框。也就是在onCreate方法中增加以下代码:
            // 从share_login.xml获取共享参数对象
            mShared = getSharedPreferences("share_login", MODE_PRIVATE);
            // 获取共享参数保存的手机号码
            String phone = mShared.getString("phone", "");
            // 获取共享参数保存的密码
            String password = mShared.getString("password", "");
            et_phone.setText(phone); // 往手机号码编辑框填写上次保存的手机号
            et_password.setText(password); // 往密码编辑框填写上次保存的密码

        代码修改完毕,只要用户上次登录成功时勾选了“记住密码”复选框,下次进入登录页面后App就会自动填写上次登录的手机号码与密码。

 更安全的数据仓库

        虽然SharedPreferences用起来比较方便,但是在一些特殊场景会产生问题。比如共享参数保存的数据较多时,初始化共享参数会把整个文件加载进内存,加载耗时可能导致主线程堵塞。又如在调用apply方法保存数据时,频繁apply容易导致线程等待超时。为此Android官方推出了数据仓库DataStore,并将其作为Jetpack库的基础组件。DataStore提供了两种实现方式,分别是Preferences DataStore和Proto DataStore,前者采用键值对存储数据,后者采用自定义类型存储数据。其中Preferences DataStore可以直接替代SharedPreferences。

        由于DataStore并未集成到SDK中,而是作为第三方框架提供,因此首先要修改模块的build.gradle文件,往dependencies节点添加下面两行配置,表示导入指定版本的DataStore库:

implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "androidx.datastore:datastore-preferences-rxjava2:1.0.0"

        数据仓库的用法类似于共享参数,首先要指定仓库名称,并创建仓库实例,示例代码如下:

private RxDataStore<Preferences> mDataStore; // 声明一个数据仓库实例

private DatastoreUtil(Context context) {
    mDataStore = new RxPreferenceDataStoreBuilder(context.getApplicationContext(), "datastore").build();
}

 // 获取数据仓库工具的实例
    public static DatastoreUtil getInstance(Context context) {
        if (instance == null) {
            instance = new DatastoreUtil(context);
        }
        return instance;
    }

        其次从仓库实例中获取指定键名的数据,下面的代码模板演示了如何从数据仓库中读取字符串值:

// 获取指定名称的字符串值
    public String getStringValue(String key) {
        Preferences.Key<String> keyId = PreferencesKeys.stringKey(key);
        Flowable<String> flow = mDataStore.data().map(prefs -> prefs.get(keyId));
        try {
            return flow.blockingFirst();
        } catch (Exception e) {
            return "";
        }
    }

        最后往仓库实例写入指定键值,下面的代码模板演示了如何将字符串写入数据仓库:

    // 设置指定名称的字符串值
    public void setStringValue(String key, String value) {
        Preferences.Key<String> keyId = PreferencesKeys.stringKey(key);
        Single<Preferences> result = mDataStore.updateDataAsync(prefs -> {
            MutablePreferences mutablePrefs = prefs.toMutablePreferences();
            mutablePrefs.set(keyId, value);
            return Single.just(mutablePrefs);
        });
    }

        前面把数据仓库的初始化以及读写操作封装在DatastoreUtil中,接下来通过该工具类即可方便的访问数据仓库了。往数据仓库保存数据的代码示例如下:

    // 从数据仓库中读取信息
    private void readDatastore() {
        DatastoreUtil datastore = DatastoreUtil.getInstance(this); // 获取数据仓库工具的实例
        String desc = "数据仓库中保存的信息如下:";
        desc = String.format("%s\n %s为%s", desc, "姓名",
                datastore.getStringValue("name"));
        desc = String.format("%s\n %s为%d", desc, "年龄",
                datastore.getIntValue("age"));
        desc = String.format("%s\n %s为%d", desc, "身高",
                datastore.getIntValue("height"));
        desc = String.format("%s\n %s为%.2f", desc, "体重",
                datastore.getDoubleValue("weight"));
        desc = String.format("%s\n %s为%b", desc, "婚否",
                datastore.getBooleanValue("married"));
        desc = String.format("%s\n %s为%s", desc, "更新时间",
                datastore.getStringValue("update_time"));
        tv_data.setText(desc);
    }

        从数据仓库获取数据的代码示例如下:

DatastoreUtil datastore = DatastoreUtil.getInstance(this); // 获取数据仓库工具的实例
datastore.setStringValue("name", name); // 添加一个名叫name的字符串
datastore.setIntValue("age", Integer.parseInt(age)); // 添加一个名叫age的整数
datastore.setIntValue("height", Integer.parseInt(height)); // 添加一个名叫height的整数
datastore.setDoubleValue("weight", Double.parseDouble(weight)); // 添加一个名叫weight的双精度数
datastore.setBooleanValue("married", isMarried); // 添加一个名叫married的布尔值
datastore.setStringValue("update_time", DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss"));

猜你喜欢

转载自blog.csdn.net/demon_dog/article/details/129261868
今日推荐