持续创造,加快成长!这是我参加「日新计划 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,设置项改写机制浅析~
飞升前篇:设置界面的开发利器Preference Library,多布局设置项完成浅析~
飞升后篇:设置界面的开发利器Preference Library,数据重建机制浅析~