Android提供的Preference组件使得APP设置页面的开发变得简单。
除了上述几篇文章讨论的Base包的Preference组件外,Android还提供了更为高效的Support包的Preference组件。
甚至于即将发布的Android Q预期将Support包的Preference组件全面替换为AndroidX包的组件。
本篇文章我们将探讨这三种Preference组件。
从Android官网的描述我们知道,Base包的Preference组件自Android 1.0(API 1)开始引入,并于Android Q(API 29)变为非推荐API。
Base包的Preference组件自打Android发布来,效力了9大版本(Android 1 ~ 9),并将在Android 10(Android Q)被正式废弃。
虽然非推荐并非禁止使用,但是官方不再维护的组件,尽量迁移至替代组件还是比较明智的选择。毕竟废弃了的API指不定埋下什么坑。
前面几篇文章花不少时间阐述了Base包的Preference组件的使用方法,原理解读和自定义方法。既然已经废弃了,那么这些探讨是不是毫无用处了呢?我觉得也不尽然,不管Preference组件再怎么变,其原理,使用方式不会差太大。
温故可以知新。
Android官方给的替代组件是AndroidX包的Preference组件。
AndroidX本是Jetpack使用的开源框架,如今Google将Support包也整合了进来。
在讲述AndroidX之前我们先介绍一下Support包下的Preference。
Support-Preference
Preference组件于版本24引入到了support V7中。
从官网的描述中我们知道support包采用RecyclerView控件展示PreferenceScreen上的组件。
使用性能更好的RecyclerView代替了ListView使得support包的Preference组件更为高效。
V7
PreferenceFragmentCompat的源码看得出来内部加载了RecyclerView控件。
// frameworks/support/v7/preference/src/android/support/v7/preference/PreferenceFragmentCompat.java public abstract class PreferenceFragmentCompat extends Fragment … { public View onCreateView(…) { … final RecyclerView listView = onCreateRecyclerView(themedInflater, listContainer, savedInstanceState); // 默认加载了RecyclerView控件 if (listView == null) { throw new RuntimeException("Could not create RecyclerView"); } mList = listView; … return view; } }
Support包的PreferenceFragmentCompat除了提供像Base包一样的addPreferencesFromResource()外还提供了如下方法。
setPreferencesFromResource()
定义:用于复写指定key的PreferenceScreen。
原理:比addPreferencesFromResource()多了一个查找目标key的PreferenceScreen的过程。
onCreatePreferences()
定义:提供给子类复写用来指定Preference布局的抽象方法。
使用:子类复写后可以调用addPreferencesFromResource()或setPreferencesFromResource()去加载布局,也可以直接创建Preference组件后手动添加到PreferenceScreen。
原理:onCreate()的最后将默认调用这个抽象方法去执行子类的配置。
除了上述的PreferenceFragmentCompat如下网址显示V7下面还有一大堆和Base包差不多名称的Preference相关类,使用方法也大同小异。
https://developer.android.google.cn/reference/android/support/v7/preference/package-summary
其中有一个类需要关注下:PreferenceViewHolder。
PreferenceViewHolder是support-v7包下加入的RecyclerView$ViewHolder子类。
内部持有title,summary等Preference内控件,用于Preference组件下缓存RecyclerView元素。
PreferenceScreen通过PreferenceGroupAdapter和RecyclerView绑定。
PreferenceGroupAdapter#onCreateViewHoler()回调时将加载Preference布局,得到itemView后封装为PreferenceViewHolder对象进行缓存。
并调用Preference#onBindViewHolder()进行初始化。
所以如果想自定义Support包的Preference组件的话需要复写onBindViewHolder()。
除了V7,V14,V17包都含有Preference组件。
V14
新引入了如下组件。
SwitchPreference和V7-SwitchPreferenceCompat一样,改了名字
PreferenceFragment 和V7-PreferenceFragmentCompat一样,改了名字
PreferenceDialogFragment 带Dialog的PreferenceFragment抽象基类
EditTextPreferenceDialogFragment 布局为输入框的PreferenceDialogFragment
ListPreferenceDialogFragment 布局为列表选择的PreferenceDialogFragment
MultiSelectListPreference 布局为列表选择的DialogPreference
MultiSelectListPreferenceDialogFragment 布局为多选列表的PreferenceDialogFragment
V17
BaseLeanbackPreferenceFragment 类似瑞士军刀风格leanback风格的PreferenceFragment抽象基类,内部集成了VerticalGridView控件
LeanbackPreferenceFragment 外层包裹了标题的BaseLeanbackPreferenceFragment子类
LeanbackSettingsFragment 根布局为LeanbackSettingsRootView的Fragment组件,主要和LeanbackPreferenceFragment配合使用
LeanbackPreferenceDialogFragment 带DialogPreference的Fragment组件
LeanbackListPreferenceDialogFragment 带List
Preference的LeanbackPreferenceDialogFragment组件
Android基于大屏幕设备推出了leanback导航模式并引入到了V17中,上述的Preference相关组件都是基于leanback风格的相应扩展组件。
AndroidX
我们回到起初说到的替代组件:AndroidX包的Preference组件。
可以跟随官方的如下说明将Support包迁移至AndroidX。
https://developer.android.google.cn/jetpack/androidx/migrate
如下网址展示了AndroidX所有的class列表。
https://developer.android.google.cn/reference/androidx/classes
Support-v7, v14下的Preference组件全部迁移到了androidx.preference包下。
Support-v17下的Preference组件全部迁移到了androidx.leanback.preference包下。
按照官方的说法。只是将Support包的代码整合到了AndroidX中。实际是不是这样呢?
AndroidX代码是开源的。
AndroidX源码网址:https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev
在Android系统的源码目录:frameworks/support/preference/src/main/java/androidx/preference/
Support VS AndroidX
将Support包和AndroidX包中最基础的Preference类分别取出并diff。
经过diff我发现两个java文件除了大量的格式,书写风格的差异以外,代码逻辑几乎完全一致。
Preference以外的文件没有diff,估计应该也是差不多的。
抛开一些注释和微小的代码优化,AndroidX果真只是针对Support包的简单整合。
我们将Base包,Support包及AndroidX包下的Preference做下总结。
Base VS Support VS AndroidX
Base包的Preference使用的ListView在性能表现,内存占用,扩展支持等方面已经落后于RecyclerView。在经历了9大版本之后即将谢幕,交棒给AndroidX。
虽然将被弃用,但其实现思路,公开API和使用文档深深地影响了Support包的Preference的设计。在Android平台上的设置模块它是当之无愧的元老。其关于Preference的设计理念也被Support和AndroidX很好地继承和发扬。
让我们一起感谢android.preference的付出,欢迎androidx.preference的到来!
--------------------------------------------------------------------------------------------------------------------------------------------------------------
20200304更新
android Q的時候frameworks/support的源碼已經從AOSP倉庫的主分支(master)裏移動到了androidx分支(androidx-master-dev),參考如下提交。
https://android-review.googlesource.com/c/platform/prebuilts/sdk/+/896475
Import Support Library, AndroidX from build 5280039
prebuilts/sdk/current/androidx-README.md文件裏可以看到説明。
如果需要查看的源碼的話,在prebuilts/sdk/current/androidx下搜索-sources.jar命名的jar包。
比如recyclerview的代碼為recyclerview-1.1.0-alpha07-sources.jar。參與編譯的為recyclerview-1.1.0-alpha07.aar。
如果需要修改代碼的話,需要切到androidx-master-dev倉庫去貢獻代碼。
這種變化使得想要在源碼裏修改support邏輯變得困難。
取得源碼自行編譯后得到class文件替換prebuilts下面的aar文件或許可行。。。
--------------------------------------------------------------------------------------------------------------------------------------------------------------