完结篇:设置界面的开发利器Preference Library,xml到界面大总结~

3,005 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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);
}
  1. requirePreferenceManager()用来校验下面使用的mPreferenceManager是否为null,是就抛出异常;

  2. 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(),我们走进去瞧一瞧 :

image.png

首先是通过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
image.png

首先判断是否为intent类型标签和extra标签 ,如果是就先进行特殊处理;否则就会调用我们前面的方法createItemFromTag()创建该节点标签对应的Preference对象,最后继续调用rInflate()递归解析创建Preference

  1. 调用方法findPreference()寻找Preference的根节点,其中查询的key是通过外部进行传的xml根节点的key值;

  2. setPreferenceScreen()真正开始设置RecyclerView的适配器以及数据源,将上面解析的Preference数据渲染到界面中:

image.png

postBindPrefeneces()方法会通过Handler发送一条消息,完成数据填充、刷新:

image.png image.png image.png

getListView()返回的就是一个RecyclerView对象,在这里设置了其适配器以及对应数据源,最终完成了xml中的数据渲染到界面上 ,完结 。

总结

Preference Library系列相关的文章到这里就更新结束了,一共写了大概十二篇文章,详细的讲述了其使用到原理分析,其实都不太难,认真看都能看的懂,希望本篇文章能给你带来帮助!!

历史文章

合体篇:设置界面的开发利器Preference Library,源码浅析一下

渡劫篇:设置界面的开发利器Preference Library,触摸事件浅析走起~

大乘篇:设置界面的开发利器Preference Library,设置项刷新机制浅析~

飞升前篇:设置界面的开发利器Preference Library,多布局设置项实现浅析~

飞升后篇:设置界面的开发利器Preference Library,数据重建机制浅析~