持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情
接下来会对
Preference Library官方库进行一个系列讲解,本篇文章是Preference Library系列的最后一篇,主要是介绍Preference Library中从xml配置设置项到渲染到界面上的整个流程。
xml渲染到界面的流程
xml渲染到屏幕上,就是在PreferenceFragmentCompat的方法onCreatePreferences()中调用了setPreferencesFromResource()实现的:
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.settings, rootKey)
}
}
所以这里我们直接从setPreferencesFromResource()开始分析。
public void setPreferencesFromResource(@XmlRes int preferencesResId, @Nullable String key) {
//1.
requirePreferenceManager();
//2.
final PreferenceScreen xmlRoot = mPreferenceManager.inflateFromResource(requireContext(),
preferencesResId, null);
final Preference root;
if (key != null) {
//3.
root = xmlRoot.findPreference(key);
if (!(root instanceof PreferenceScreen)) {
throw new IllegalArgumentException("Preference object with key " + key
+ " is not a PreferenceScreen");
}
} else {
root = xmlRoot;
}
//4.
setPreferenceScreen((PreferenceScreen) root);
}
-
requirePreferenceManager()用来校验下面使用的mPreferenceManager是否为null,是就抛出异常; -
inflateFromResource()真正触发xml的解析加载,我们详细分析下:
public PreferenceScreen inflateFromResource(@NonNull Context context, int resId,
@Nullable PreferenceScreen rootPreferences) {
//...
final PreferenceInflater inflater = new PreferenceInflater(context, this);
rootPreferences = (PreferenceScreen) inflater.inflate(resId, rootPreferences);
//...
return rootPreferences;
}
关键就是调用了方法PreferenceInflater.inflate(),我们走进去瞧一瞧 :
首先是通过xml资源id拿到了解析类XmlResourceParser对象,接着继续调用方法inflate():
public Preference inflate(XmlPullParser parser, @Nullable PreferenceGroup root) {
synchronized (mConstructorArgs) {
final Preference result;
try {
Preference xmlRoot = createItemFromTag(parser.getName(),
attrs);
result = onMergeRoots(root, (PreferenceGroup) xmlRoot);
rInflate(parser, result, attrs);
}
return result;
}
}
上面是精简后的代码,可以看到和我们在Activity中解析布局xml的逻辑基本上都是相同的:
- 借助
createItemFromTag()获取设置项的标签,并反射加载获取,最终的实现逻辑在createItem()方法中:
private Preference createItem(@NonNull String name, @Nullable String[] prefixes,
AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor<?> constructor = CONSTRUCTOR_MAP.get(name);
try {
if (constructor == null) {
final ClassLoader classLoader = mContext.getClassLoader();
Class<?> clazz = Class.forName(name, false, classLoader);
//...
constructor = clazz.getConstructor(CONSTRUCTOR_SIGNATURE);
constructor.setAccessible(true);
CONSTRUCTOR_MAP.put(name, constructor);
}
Object[] args = mConstructorArgs;
args[1] = attrs;
return (Preference) constructor.newInstance(args);
}
}
先尝试从对象池CONSTRUCTOR_MAP中获取当前标签对应类的构造器,如果存在直接调用newInstance()方法反射创建一个Preference对象;
如果缓存池中不存在标签类的构造器,那就通过Class.forName()方法创建标签类的构造器,紧接着加入到缓存CONSTRUCTOR_MAP中,最终和上面一样调用newInstance()创建对象。
rInflate()递归解析创建Preference
首先判断是否为intent类型标签和extra标签 ,如果是就先进行特殊处理;否则就会调用我们前面的方法createItemFromTag()创建该节点标签对应的Preference对象,最后继续调用rInflate()递归解析创建Preference。
-
调用方法
findPreference()寻找Preference的根节点,其中查询的key是通过外部进行传的xml根节点的key值; -
setPreferenceScreen()真正开始设置RecyclerView的适配器以及数据源,将上面解析的Preference数据渲染到界面中:
postBindPrefeneces()方法会通过Handler发送一条消息,完成数据填充、刷新:
getListView()返回的就是一个RecyclerView对象,在这里设置了其适配器以及对应数据源,最终完成了xml中的数据渲染到界面上 ,完结 。
总结
Preference Library系列相关的文章到这里就更新结束了,一共写了大概十二篇文章,详细的讲述了其使用到原理分析,其实都不太难,认真看都能看的懂,希望本篇文章能给你带来帮助!!
历史文章
合体篇:设置界面的开发利器Preference Library,源码浅析一下
渡劫篇:设置界面的开发利器Preference Library,触摸事件浅析走起~
大乘篇:设置界面的开发利器Preference Library,设置项刷新机制浅析~