Android O Settings
数据加载之一级菜单
DashboardSummary是顶级菜单的容器,那么数据的获取和它也就有关系。
DashboardCategory的获取是在DashboardSummary中的updateCategoryAndSuggestion方法中,获取之后在DashboardAdapter设置
根据"com.android.settings.category"的值查询子项数据,这里的值为"com.android.settings.category.ia.homepage"。
在DashboardSummary的onCreate函数中有获取的有两个很重要数:mDashboardFeatureProvider,mSuggestionFeatureProvider.这两个是主要的数据提供者,mSuggestionFeatureProvider和mDashboardFeatureProvider的数据获取是有所不同的,重点说明下mDashboardFeatureProvider.
mDashboardFeatureProvider提供的数据是一级菜单如"电池","显示","网络和互联网"等,
实现类为DashboardFeatureProviderImpl.java,而DashboardFeatureProviderImpl中的具体的数据是通过函数getTilesForCategory()从CategoryManager获取的.
CategoryManager是SettingsLib这个静态包中公共类,可以看一下:
可以看到CategoryManager是一个单例类型,这里就是真正的数据加载位置,
加载是通过函数reloadAllCategories()调用tryInitCategories()获取的.
到这里为止,整个数据获取的流程已经清楚,但是数据加载是在哪里完成的呢,还要回到SettingsDrawerActivity中:
因为DashboardSummary启动的生命周期已经结束,主要是完成一些对象的初始化工作(无数据),需要继续分析Setting的onResume周期,最终调用的是SettingsDrawerActivity的onResume()方法。
在SettingsDrawerActivity中注册了安装应用状态变化的广播接收器等,但是这里还进行了一个异步操作:
new CategoriesUpdateTask().execute();
在这个AsyncTask中,doInBackground()调用了CategoryManager的reloadAllCategories()函数,而onPostExecute则调用了接口CategoryListener的唯一方法onCategoriesChanged(),那么作为界面容器的DashboardSummary肯定重载了这个接口,实现了onCategoriesChanged()方法:
DashboardSummary在方法onCategoriesChanged()中进行了界面的刷新,
mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this, getSettingPkg());
reloadAllCategories函数中调用了tryInitCategories(),此函数中是获取数据以及对数据的处理,来看下函数tryInitCategories:
在这里调用了getCategories()方法;
具体获取办法追踪到frameworks\base\packages\SettingsLib\src\com\android\settingslib\drawer\TileUtils.java中。
TileUtils.java:
(1)调用getTilesForAction()
(2)新建categoryMap集合
(3)遍历tiles,判断集合中是否有元素含有tile.category,如果没有就执行createCategory
(4)将拥有相同属性category的tile加入到对象DashboardCategory category对象的list<tile>集合中(两个相同名字,一个是Tile里面变量,一个是DashboardCategory对象)
(5)将categoryMap的值赋值给List <DashboardCategory>cagtories以便执行排序算法
(6)遍历cagtories利用Collections函数和比较器TILE_COMPARATOR将category.tiles按照priority从大到小排序
(7)利用Collections函数和比较器CATEGORY_COMPARATOR将categories按照priority从大到小排序
最后将加载的数据绑定到适配器中。
首先是getTilesForAction()方法,组装Intent对象。
然后调用getTilesForIntent()方法
(1)利用PM查询所有含有getTilesForAction()生成的intent对象的ResolveInfo集合(<activity>标签)
(2)获取集合中每一个AcitvityManifest配置的meta标签name包含com.android.settings.category的value值
(3)把activity name 和package 生成Intent对象
(4)将2步骤的值赋值给tile .category
(5)获取action为com.android.settings.action.SETTINGS的intent-filter的priority属性
(6)将解析meta-data标签的bundle数据赋值给tile.metaData
注意:会过滤掉非系统级应用的数据!
在此方法中会调用updateTileData()方法
(1) 解析meta-data标签 获取name为 META_DATA_PREFERENCE_ICON的value值赋值给icon
(2)解析meta-data标签 获取name为 META_DATA_PREFERENCE_TITLE的resource值赋值给title
(3)解析meta-data标签 获取name为 META_DATA_PREFERENCE_SUMMARY的value值赋值给summary
(4)如果title为空就获取acitvity标签label属性赋值给title
(5)如果icon等于0就获取acitvity标签icon属性赋值给icon
createCategory()方法创建Category。
(1)创建DashboardCategory对象
(2)利用PM查询所有含有Tile对象categoriyKey生成的intent对象的ResolveInfo集合
(3)把acitivity label值赋值给category title属性
(4)把解析intent-filter标签的priority值赋值给category属性
对于第一级菜单的加载。在AndroidManifest.xml中的配置如下列图:(示例)
配置完之后会在onCategoriesChanged()中进行界面的加载。
由此可以知道 第一级菜单完全是动态加载!