Preference组件探究之Base,Support及AndroidX对比

简介: Preference组件探究之Base,Support及AndroidX对比

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。

1832b220aa754cd18c504acc7686a560.png

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

1832b220aa754cd18c504acc7686a560.png

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。

1832b220aa754cd18c504acc7686a560.png

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,估计应该也是差不多的。

1832b220aa754cd18c504acc7686a560.png

抛开一些注释和微小的代码优化,AndroidX果真只是针对Support包的简单整合。

我们将Base包,Support包及AndroidX包下的Preference做下总结。

Base VS Support VS AndroidX

1672144177885.png

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文件或許可行。。。


--------------------------------------------------------------------------------------------------------------------------------------------------------------



相关文章
|
Java API 调度
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
1145 0
|
Android开发
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
2946 1
|
开发工具 Android开发
解决bug:运行项目时报异常 “Can't create handler inside thread that has not called Looper.prepare()”
解决bug:运行项目时报异常 “Can't create handler inside thread that has not called Looper.prepare()”
1566 0
|
API 开发工具 Android开发
Android Studio:解决AOSP自编译framework.jar引用不到的问题
在Android Studio中解决AOSP自编译framework.jar引用问题的几种方法,包括使用相对路径、绝对路径和通过`${project.rootDir}`动态获取路径的方法,以避免硬编码路径带来的配置问题。
1331 0
Android Studio:解决AOSP自编译framework.jar引用不到的问题
|
存储 缓存 Java
Android性能优化:内存管理与LeakCanary技术详解
【7月更文挑战第21天】内存管理是Android性能优化的关键部分,而LeakCanary则是进行内存泄漏检测和修复的强大工具。
|
Java 开发者 Kotlin
深入理解Kotlin中的伴生对象
【8月更文挑战第31天】
285 0
|
应用服务中间件 API nginx
[nginx]lua控制请求头
[nginx]lua控制请求头
284 0
|
XML Java Android开发
Android Studio App开发中工具栏Toolbar、溢出菜单OverflowMenu、标签布局TabLayout的讲解及实战(实现京东App的标签导航栏,附源码)
Android Studio App开发中工具栏Toolbar、溢出菜单OverflowMenu、标签布局TabLayout的讲解及实战(实现京东App的标签导航栏,附源码)
1094 0
|
Java API Maven
一篇文章讲明白Jetty使用教程(一)——开始使用Jetty
一篇文章讲明白Jetty使用教程(一)——开始使用Jetty
691 0
|
Java Shell Android开发
Android11 有线网和wifi优先级设置
Android11 有线网和wifi优先级设置
1085 0