(一百九十)Android Jetpack 学习(四)—— 偏好设置

前言:偏好设置如果是负责设置模块的同学就会非常熟悉,我虽然很熟悉,但是没有系统地看过官方文档,都是看参考设置以及学习设置源码的,也许会有所缺漏。

学习:https://developer.android.google.cn/guide/topics/ui/settings

 

设置   

注意:本指南介绍如何使用 AndroidX Preference Library。自 Android 10 开始,系统已弃用 android.preference 库平台。

设置使用户能够改变应用的功能和行为。设置可以影响后台行为,例如应用与云同步数据的频率;设置的影响还可能更为深远,例如改变用户界面的内容和呈现方式。

建议使用 AndroidX Preference Library 将用户可配置设置集成至您的应用中。此库管理界面,并与存储空间交互,因此您只需定义用户可以配置的单独设置。此库自带 Material 主题,可在不同的设备和操作系统版本之间提供一致的用户体验。

 

简单入门的参考https://developer.android.google.cn/guide/topics/ui/settings

本文主要学习下之前有缺漏的部分

 

Control Preference 可见性

您可以在用户跳转至设置屏幕时,控制哪些 Preferences 对用户可见。 例如,如果某个特定 Preference 仅在对应功能启用时才有意义,则您可能想在该功能停用时隐藏该 Preference

要仅在符合某项条件时显示 Preference,首先要在 XML 中将 Preference 可见性设置为 false,如以下示例所示:


接下来,当符合相应条件时,在 onCreatePreferences() 中显示 Preference

KotlinJava

@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
    setPreferencesFromResource(R.xml.preferences, rootKey);
    if(*/\*some feature\*/*) {
        Preference editTextPreference = findPreference("signature");
        editTextPreference.setVisible(true);
    }
}

这边学习一下,之前项目的实现是默认显示,代码里动态判断若不支持则移除对应preference

这边官方文档提供另外一种思路,默认隐藏,动态判断支持则显示出来

 

使用自定义 SummaryProvider

无论 Preference 何时请求摘要,您都可以创建自己的 SummaryProvider,并替换 provideSummary(),以自定义摘要。 例如,下面的 EditTextPreference 展示了其作为摘要保存的值的长度:

(一百九十)Android Jetpack 学习(四)—— 偏好设置_第1张图片

举例来说,假设以下 EditTextPreference


onCreatePreferences() 中,新建 SummaryProvider,然后替换 provideSummary() 以返回要显示的摘要:

KotlinJava

EditTextPreference countingPreference = (EditTextPreference) findPreference("counting");

countingPreference.setSummaryProvider(new SummaryProvider() {
    @Override
    public CharSequence provideSummary(EditTextPreference preference) {
        String text = preference.getText();
        if (TextUtils.isEmpty(text)){
            return "Not set";
        }
        return "Length of saved value: " + text.length();
    }
});

现在,Preference 摘要显示保存的值的长度,如果 不存在保存的值,则显示“未设置”。

这里有代码动态根据preference的值设定summary的方法,这块没实际用过。

 

 

首选项操作

Preference 在点按时可执行特定操作。 例如,Preference 可以用作关联应用某个单独部分的链接。 要为 Preference 添加操作,您可以直接在 Preference 上设置 Intent,或设置 OnPreferenceClickListener,以获得更具体的逻辑。

设置 Intent

您可以在 Preference 上设置 Intent,以在每次点按 Preference 时,启用新的 FragmentActivity、或单独的应用。 这等同于使用给定 IntentContext.startActivity()

您可以使用嵌套 标签在 XML 中设置 Intent。 下方示例定义了启动 ActivityIntent


    

或者,您也可以在 Preference 上直接使用 setIntent(),如下所示:

KotlinJava

Intent intent = new Intent(getContext(), ExampleActivity.class);
activityPreference.setIntent(intent);

您还可以通过 XML,添加带有 Intent 的 extras:


    
        
    

以下为 Preference 的示例,其中带有启动网页的 Intent


    

KotlinJava

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.google.com"));
webpagePreference.setIntent(intent);

OnPreferenceClickListener

您可以在 Preference 上设置 OnPreferenceClickListener,当点按 Preference 时,此操作会为 onPreferenceClick() 添加回调。 例如,如果您有更复杂的逻辑可以用于处理跳转,则可以使用侦听器跳转至另一个 FragmentActivity

要设置 OnPreferenceClickListener,请使用与下方所示内容类似的代码:

KotlinJava

onClickPreference.setOnPreferenceClickListener(preference -> {
    // do something
    return true;
});

这点击事件其实没啥说的,现在Android PreferenceController都封装好了,不用单独设置了。

 

 

SharedPreferences

默认情况下,Preference 使用 SharedPreferences 保存值。 SharedPreferences API 支持从在各个应用会话中保存的文件中,读取和写入简单的键值对。

Preference Library 使用不公开的 SharedPreferences 实例,因此只有您的应用可以访问该库。

举例来说,我们假设以下 SwitchPreferenceCompat


如果用户将此开关切换至 On 状态,则 SharedPreferences 文件使用 "notifications" : "true" 键值对更新。 请注意,所用密钥与为 Preference 设置的密钥一致。

如需更多有关 SharedPreferences API 的信息,请参阅 保存键值数据。

如要详细了解在 Android 上存储数据的不同方法,请参阅 数据和文件存储概览。

但是实际上并不会用preference的这个特性存储值,因为Settings的preference的功能不光是Settings自己的事,更多的是服务于整个安卓系统,一般会保存到SettingsProvider中或者有特定的api接口可以设置和读取。

 

读取首选项值

要检索正在使用的 SharedPreferences 对象,请调用 PreferenceManager.getDefaultSharedPreferences()。 此方法适用于您应用的任何位置。 例如,给定一个密钥为“signature”的 EditTextPreference


您可以对此 Preference 的保存值进行全局检索,方法如下:

KotlinJava

SharedPreferences sharedPreferences =
        PreferenceManager.getDefaultSharedPreferences(this /* Activity context */);
String name = sharedPreferences.getString(“signature”, "");

 

这个最近刚用到过,这个方法本质上是拼接了包名等信息生成SharedPreference的xml保存到应用目录下。

 

 

侦听首选项值的变化

要侦听 Preference 值的变化,您可以在两个接口中选择一个:

  • Preference.OnPreferenceChangeListener
  • SharedPreferences.OnSharedPreferenceChangeListener

下表展示了两个接口的差别:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
针对每个首选项进行设置 应用于所有首选项
在首选项要改变其保存的值时进行调用。 如果待处理的值与当前保存的值相同,则其也包括在内。 只在为首选项保存的值发生变化时调用。
只通过 Preference Library 调用。 应用的单独部分可以改变保存的值。 随保存值的变动进行调用,即便该值来自应用的单独部分也是如此。
在待处理的值保存前调用。 在该值保存后调用。
在使用 SharedPreferencesPreferenceDataStore 时调用。 只在使用 SharedPreferences 时调用。

OnPreferenceChangeListener

执行 OnPreferenceChangeListener 使您能够侦听Preference 的值将在何时出现变动。 由此,您可以验证此变动是否应该发生。 例如,以下代码展示了如何侦听密钥为“name”的 EditTextPreference 值的变化:

KotlinJava

@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
    Log.e("preference", "Pending Preference value is: " + newValue);
    return true;
}

接下来,您需要直接使用 setOnPreferenceChangeListener() 设置此侦听器,如下所示:

KotlinJava

preference.setOnPreferenceChangeListener(...);

OnSharedPreferenceChangeListener

在使用 SharedPreferences 保留 Preference 值时,您还可以使用 SharedPreferences.OnSharedPreferenceChangeListener 侦听变动。 这使您能够侦听 Preference 保存的值在何时出现变动,例如在与服务器同步设置时。 以下示例展示了如何侦听密钥为“name”的 EditTextPreference 值 出现变动的时间:

KotlinJava

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    if (key.equals(“signature”)) {
        Log.i(TAG, “Preference value was updated to: “ + sharedPreferences.getString(key, ""));
    }
}

此外,您必须通过 registerOnSharedPreferenceChangedListener() 注册侦听器,如下所示:

KotlinJava

getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(...);

警告:为避免意外的垃圾回收,您必须存储对侦听器的强引用。 在您调用 registerOnSharedPreferenceChangeListener()时,SharedPreferenceManager 不会存储对侦听器的强引用。 为解决这一问题,您可直接在 PreferenceFragmentCompat 中执行 onSharedPreferenceChanged()。 您还可以创建一个实例变量,如下所示:

KotlinJava

SharedPreferences.OnSharedPreferenceChangeListener listener =
        new SharedPreferences.OnSharedPreferenceChangeListener() {...}

为妥善管理 ActivityFragment 的生命周期,您应使用 onResume()onPause() 回调完成此侦听器的注册和取消注册,如下所示:

KotlinJava

@Override
public void onResume() {
    super.onResume();
    getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}

@Override
public void onPause() {
    super.onPause();
    getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}

学习了下OnSharedPreferenceChangeListener的使用,可以监听preference的总体变化,但感觉没啥用。。。

 

 

使用自定义数据存储

虽然推荐使用 SharedPreferences 保留 Preference,但您也可以使用自定义数据存储。 如果您的应用将值保留至数据库,又或者值专门针对设备,这时自定义数据存储会非常有用,如示例所示。

采用数据存储

要采用自定义数据存储,先要创建一个扩展 PreferenceDataStore 的类。 以下示例创建了一个处理 String 值的数据存储:

KotlinJava

public class DataStore extends PreferenceDataStore {
    @Override
    public void putString(String key, @Nullable String value) {
        // Save the value somewhere
    }
    @Override
    @Nullable
    public String getString(String key, @Nullable String defValue) {
        // Retrieve the value
    }
}

请注意:只需替换您 Preference 对象所使用的方法。 试图调用您尚未实现的方法会导致 UnsupportedOperationException

确保不在主线程上执行任何耗时操作,以避免堵塞用户接口。 由于在保留值的过程中,包含数据存储的 FragmentActivity 可能会被销毁,所以您应该将数据序列化,以防丢失用户更改的任何值。

启用数据存储

采用数据存储后,您必须在 onCreatePreferences() 中设置新的数据存储,以便 Preference 对象使用数据存储保留值,而非使用默认的 SharedPreferences。 您可以针对每个 Preference 或整个层次结构启用数据存储。

要为特定 Preference 启用自定义数据存储,请调用 Preference 上的 setPreferenceDataStore(),如以下示例所示:

KotlinJava

Preference preference = findPreference(“key”);
preference.setPreferenceDataStore(dataStore);

要为整个层次结构启用自定义数据存储,请调用 PreferenceManager 上的 setPreferenceDataStore()

KotlinJava

PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setPreferenceDataStore(dataStore);

为特定 Preference 设置的数据存储将替换为对应层次结构设置的任何数据存储。 大多数情况下,您需要为整个层次结构设置一个数据存储。

请注意:如果您在 Preference 附加到层次结构后,再为某个 Preference 设置数据存储,则 Preference 的初始值将不再传播。

这里的PreferenceDataStore看起来自定义了数据存储,但是不可避免的将一堆preference的数据存储放在了一个类里,然后可以预见到一堆if else的代码结构,没有现在Android用的PreferenceController好

 

 

 

你可能感兴趣的:(Android)