Setting 模块的界面渲染的时候说过,setting 的主界面(一级菜单),是通过 DashboardSummary 来加载的,DashboardSmmary 作为设置主界面的顶部容器,自然与数据的加载也有关。DashboardSummary 是 Fragment 的子类,所以也要执行 onCreate()方法:
可以看到在 onCreate()方法里面有两个数据提供者 mDashboardFeatureProvider,mSuggestionFeatureProvider,这两个是很重要的数据提供者,但是他们两个获取的数据是不同的,这里着重看一下 mDashboardFeatureProvider,它提供的数据是一级菜单如”电池”,”显示”,”网络和互联网”等。
FeatureFactory 其为单例模式,返回的是 FeatureFactoryImpl 对象,而 FeatureFactoryImpl 对象的 getDashboardFeatureProvider 方法,返回的是 DashboardFeatureProviderImpl 对象: \packages\apps\settings\src\com\android\settings\overlay\FeatureFactoryImpl.java然后执行:
其传入的参数为 当前的 activity 以及 CategoryKey.CATEGORY_HOMEPAGE 字串
可以看到 Category,类别对象是通过 DashboardFeatureProviderImpl 的 getTilesForCategory 方法,因为 DashboardFeatureProviderImpl 是 mDashboardFeatureProvider 的实现
packages\apps\settings\src\com\android\settings\dashboard\DashboardFeatureProviderImpl.javaDashboardFeatureProviderImpl:
mCategoryManager 的初始化时在 DashboardFeatureProviderImpl 的构造方法中,使用 CategoryManager 的静态方法 get 获取的:
其构造方法初始化一些参数,再看 CategoryManager 的 getTilesByCategory 方法:
然后调用了tryInitCategories方法:
由于是第一次进入,mCategories 并没有初始化过,因此会走入 if 条件,然后调用 TileUtils.java 的 getCategories 方法,初始化 mCategories 的数据,注意传入的参数为 context
frameworks\base\packages\settingslib\src\com\android\settingslib\drawer\TileUtils.java现在来详细看看 getCategories 方法:
- 首先调用调用了 getTilesForAction()方法
- 调用 getTilesForIntent 方法
- getTilesForIntent 中调用 updateTileData 方法:
- getTilesForIntent 中调用 addedCache.put(key, tile)方法
- 回到 getCategories 方法,在 getTilesForAction 方法后执行了 createCategory 方法
(1)创建DashboardCategory对象
(2)利用PM查询所有含有Tile对象categoriyKey生成的intent对象的ResolveInfo集合
(3)把acitivity label值赋值给category title属性
(4)把解析intent-filter标签的priority值赋值给category属性
通过 createCategory 方法,创建 DashboardCategory,并且根据 tile 的 category 来进行分类,最终 getCategories 方法会返回包含多个 DashboardCategory 的 ArrayList
除了注册了一个广播接收器,还执行了一个异步操作:new CategoriesUpdateTask().execute()
可以看到在异步任务里面除了调用了 reloadAllCategories()方法一直加载数据以外,还调用了接口 CategoryListener 的唯一方法 onCategoriesChanged(),那么作为界面容器的 DashboardSummary 肯定重载了这个接口,实现了 onCategoriesChanged()方法,回到 DashboardSummary:
在 onCategoriesChanged 中调用了 rebuildUI 方法,从注释中可以看到,其实第一次启动时,在 DashboardSummary 的 onViewCreated 的方法中也调用了 rebuildUI()
onViewCreated 的两个作用
1. 初始化DashboardAdapter, 并设置到mDashboard中
2. 重新更新UI
现在就来看看 rebuildUI()方法:
在 rebuildUI 中无论条件判断进入那个分支,都会执行 updateCategoryAndSuggestion 方法,不论是否支持 Suggestion,最终都会调用 updateCategoryAndSuggestion 方法,并且传入的参数为 null
调用 DashboardAdapter 的 setCategory 方法,设置获取到的 DashboardCategory
最后调用 DashboardAdapter 的 setCategory 方法,设置获取到的 DashboardCategory
可以知道第一级菜单完全是动态加载的DashboardSummary 在 onCreateView 加载的布局 R.layout.dashboard,是一个 recycleview
在 onViewCreated 方法获取到 recycleview 控件,然后设置获取到的 DashboardAdapter
有两种情况,一种是一级菜单是 activty,还有一种是一级菜单是 fragment
一级菜单项的实现是 activity因为是通过 activity 实现的,通过直接继承 activity,实现比较简单 首先,在 AndroidManifest.xml 清单中添加要添加的菜单项,以 HardKey.java 为例
然后,再自己实现 HardKey.java 这个 activity,自己实现他的布局和具体逻辑。
一级菜单项的实现是 fragment首先也是在 AndroidManifest.xml 清单中添加:
然后自己实现 FlashSettingsActivity.java 这个 fragment 最后在 Setting.java 里面添加:
public static class FlashSettingsActivity extends SettingsActivity { /_ empty _/ } 总结:其实我们添加 FlashSettingsActivity 这个并不是一个 activity,这只是 SetttingsActivity 的一个子类,而且是空实现,之所以要添加这个空的 activity,是为了外部应用能够跳转到 FlashSettingsActivity 界面,如果是 fragment 的话,外部应用是无法直接跳转到 fragment 的,当点击跳转后,会执行 SetttingsActivity 中的方法,根据其在 AndroidManifest 清单文件中的注册信息,它的的 mata-data 信息,找到“com.android.settings.FRAGMENT_CLASS”,然后加载对应的 fragment,一般在 AndroidManifest 中会声明称 settings 的内部类: android:name=”Settings$FlashSettingsActivity” 在尝试修改 priority=”9”会发现,mmm 模块编译安装到手机之后发现位置没有改变啊。其实这个 priority=”9”的判断是在 frameworks 中进行处理的,所以只有编译 frameworks 之后才会生效。