炼虚篇:设置界面的开发利器Preference Library,了解一下~

999 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

接下来会对Preference Library官方库进行一个系列讲解,本篇文章是Preference Library系列的第四篇,主要是介绍Preference Library如何实现设置项配置变化监听。

历史文章

练气篇:设置界面的开发利器Preference Library,了解一下~

筑基篇:设置界面的开发利器Preference Library,了解一下~

金丹篇:设置界面的开发利器Preference Library,了解一下~

元婴篇:设置界面的开发利器Preference Library,了解一下~

Preference Library实现设置项配置变化监听有两种方式:

  1. Preference.OnPreferenceChangeListener

  2. SharedPreferences.OnSharedPreferenceChangeListener

具体的区别如下(来自官方):

image.png

在讲解这四大区别之前,我们先看下这两种方式对应的代码逻辑是如何实现的:

实现方式

1. Preference.OnPreferenceChangeListener

调用方法setOnPreferenceChangeListener()

findPreference<Preference>("develop")?.let {
    it.setOnPreferenceChangeListener { preference, newValue ->
        
        return@setOnPreferenceChangeListener true
    }
}

2. SharedPreferences.OnSharedPreferenceChangeListener

val listener: SharedPreferences.OnSharedPreferenceChangeListener =
    SharedPreferences.OnSharedPreferenceChangeListener {
        
    }

preferenceManager.sharedPreferences?.registerOnSharedPreferenceChangeListener(listener)

这个地方有个非值得注意的地方:

通过registerOnSharedPreferenceChangeListener()注册的监听器是保存到SharedPreferenceImpl的弱引用集合中的:

private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
            new WeakHashMap<OnSharedPreferenceChangeListener, Object>();

@Override
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
    synchronized(mLock) {
        mListeners.put(listener, CONTENT);
    }
}

就是因为写入到的一个是弱引用集合 ,所以一旦发生GC这个对象就直接回收了,我们的监听也就没啥作用的了,所以我们需要在外部持有一个强引用才行。

接下来我们就分别讲讲区别。

两种监听变化的区别

1. 应用范围不同

  • Preference.OnPreferenceChangeListener是为了单独设置给某个Preference设置项使用的,不和其他设置项共享使用;

  • SharedPreferences.OnSharedPreferenceChangeListener是设置给所有的配置项使用的,全局共享;

2. 监听范围不同

  • Preference.OnPreferenceChangeListener只要值发生了变化就会回调,包括了这个变化后的值和之前保存的值相同,监听范围更广;

  • SharedPreferences.OnSharedPreferenceChangeListener只有在值发生了变化之后才进行调用,也就是说值不发生变化,就不会回调该对象;

3. 回调时机不同

  • Preference.OnPreferenceChangeListener是在设置项的配置值写入到本地之前进行调用;

  • SharedPreferences.OnSharedPreferenceChangeListener是在设置项的配置值写入到本地之后进行调用;

4. 作用范围不同

  • Preference.OnPreferenceChangeListener不论是你使用默认SharedPreference存储还是其他自定义存储库,只要值发生变化,就可以收到这个回调;

  • SharedPreferences.OnSharedPreferenceChangeListener从其名字就可以看出来,专门用户官方SharedPreference监听使用的,如果你自定义存储,那这个回调就无效了;

5. 响应范围不同

  • Preference.OnPreferenceChangeListener只有因Preference Library这个库引发的设置项配置变化才能收到回调,也就是说,如果在其他和Preference Library库实现无关的界面上(比如应用主界面等等),你手动获取SharedPreference去修改这个值,那这个监听将是无效的;

  • SharedPreferences.OnSharedPreferenceChangeListener设置的SharedPreference监听是全局的,也就是说,只要在这个应用的任何地方触发了配置值的更改,那就可以收到回调,可以说是相当的强大。

但这样就会引入一个问题,如果你已经不再设置界面了,你为啥还要监听配置值的变化,一旦设置界面销毁了你还在监听变化,这不是很容易引发内存泄漏吗?(创建的OnPreferenceChangeListener会持有外部类FragmentActivity的引用),所以我们需要管理监听器的注册和反注册

代码如下:

val listener: SharedPreferences.OnSharedPreferenceChangeListener =
    SharedPreferences.OnSharedPreferenceChangeListener {

    }

override fun onResume() {
    super.onResume()
    preferenceManager.sharedPreferences?.registerOnSharedPreferenceChangeListener(listener)

}

override fun onPause() {
    super.onPause()
    preferenceManager.sharedPreferences?.registerOnSharedPreferenceChangeListener(listener)
}

总结

本篇文章主要是讲解了如何实现Preference Library中设置项配置值变化的监听,主要是有两种方式并分析了区别,希望能给你带来帮助。