上一节讲到界面加载流程
本节来讲以Setting根界面Dashboard为例解析数据加载流程
首先看到继续上一节launchSettingFragment()方法
switchToFragment(DashboardSummary.class.getName(), null /* args */, false, false, mInitialTitleResId, mInitialTitle, false);
很明显这里是加载的DashboardSummary.java这个类,我们打开这个类,看到onCreateView方法。
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { long startTime = System.currentTimeMillis(); final View root = inflater.inflate(R.layout.dashboard, container, false); mDashboard = root.findViewById(R.id.dashboard_container); mLayoutManager = new LinearLayoutManager(getContext()); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); if (bundle != null) { int scrollPosition = bundle.getInt(STATE_SCROLL_POSITION); mLayoutManager.scrollToPosition(scrollPosition); } mDashboard.setLayoutManager(mLayoutManager); mDashboard.setHasFixedSize(true); mDashboard.setListener(this); mDashboard.setItemAnimator(new DashboardItemAnimator()); mAdapter = new DashboardAdapter(getContext(), bundle, mConditionManager.getConditions(), mSuggestionControllerMixin, getLifecycle()); mDashboard.setAdapter(mAdapter); mSummaryLoader.setSummaryConsumer(mAdapter); ActionBarShadowController.attachToRecyclerView( getActivity().findViewById(R.id.search_bar_container), getLifecycle(), mDashboard); rebuildUI(); if (DEBUG_TIMING) { Log.d(TAG, "onCreateView took " + (System.currentTimeMillis() - startTime) + " ms"); } return root; }
R.layout.dashboard 这个dashboard.xml本身是一个Recyclerview的控件布局,上面的代码大部分都是在对界面和recyclerview进行设置和基本的通用布局导入,直接看rebuildUI这个方法。rebuildUI中只有一个方法updateCategory(),阅读代码段。
@WorkerThread void updateCategory() { final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory( CategoryKey.CATEGORY_HOMEPAGE); mSummaryLoader.updateSummaryToCache(category); mStagingCategory = category; Log.d(TAG," updateCategory mSuggestionControllerMixin = " + mSuggestionControllerMixin); if (mSuggestionControllerMixin == null) { ThreadUtils.postOnMainThread(() -> mAdapter.setCategory(mStagingCategory)); return; } if (mSuggestionControllerMixin.isSuggestionLoaded()) { Log.d(TAG, "Suggestion has loaded, setting suggestion/category"); ThreadUtils.postOnMainThread(() -> { if (mStagingSuggestions != null) { mAdapter.setSuggestions(mStagingSuggestions); } mAdapter.setCategory(mStagingCategory); }); } else { Log.d(TAG, "Suggestion NOT loaded, delaying setCategory by " + MAX_WAIT_MILLIS + "ms"); mHandler.postDelayed(() -> mAdapter.setCategory(mStagingCategory), MAX_WAIT_MILLIS); } }
CategoryKey.CATEGORY_HOMEPAGE 实际上就是 com.android.settings.category.ia.homepage,也就是说category是从AndroidManifest文件解析 <meta-data android:name="com.android.settings.category" 对应属性值为com.android.settings.category.ia.homepage的Activity来获得。
下面看到getTilesForCategory这个方法,它是接口DashboardFeatureProvider中的一个方法,其实现类是DashboardFeatureProviderImpl.java阅读代码可以发现getTilesForCategory里面返回的实际上是CategoryManager.getTilesByCategory这个方法。ps:/frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) { return getTilesByCategory(context, categoryKey, TileUtils.SETTING_PKG); } public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey, String settingPkg) { tryInitCategories(context, settingPkg); return mCategoryByKeyMap.get(categoryKey); } private synchronized void tryInitCategories(Context context, String settingPkg) { // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange // happens. tryInitCategories(context, false /* forceClearCache */, settingPkg); } private synchronized void tryInitCategories(Context context, boolean forceClearCache, String settingPkg) { if (mCategories == null) { if (forceClearCache) { mTileByComponentCache.clear(); } mCategoryByKeyMap.clear(); mCategories = TileUtils.getCategories(context, mTileByComponentCache, false /* categoryDefinedInManifest */, mExtraAction, settingPkg); for (DashboardCategory category : mCategories) { mCategoryByKeyMap.put(category.key, category); } backwardCompatCleanupForCategory(mTileByComponentCache, mCategoryByKeyMap); sortCategories(context, mCategoryByKeyMap); filterDuplicateTiles(mCategoryByKeyMap); } }
从红色的代码可以看到,使用的是TileUtils.getCategories()方法获取得到category。
/** * Build a list of DashboardCategory. * @param categoryDefinedInManifest If true, an dummy activity must exists in manifest to * represent this category (eg: .Settings$DeviceSettings) * @param extraAction additional intent filter action to be usetileutild to build the dashboard * categories */ public static List<DashboardCategory> getCategories(Context context, Map<Pair<String, String>, Tile> cache, boolean categoryDefinedInManifest, String extraAction, String settingPkg) { final long startTime = System.currentTimeMillis(); boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0) != 0; ArrayList<Tile> tiles = new ArrayList<>(); UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); for (UserHandle user : userManager.getUserProfiles()) { // TODO: Needs much optimization, too many PM queries going on here. if (user.getIdentifier() == ActivityManager.getCurrentUser()) { // Only add Settings for this user. getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true, settingPkg); getTilesForAction(context, user, OPERATOR_SETTINGS, cache, OPERATOR_DEFAULT_CATEGORY, tiles, false, true, settingPkg); getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache, MANUFACTURER_DEFAULT_CATEGORY, tiles, false, true, settingPkg); } if (setup) { getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false, settingPkg); if (!categoryDefinedInManifest) { getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false, settingPkg); if (extraAction != null) { getTilesForAction(context, user, extraAction, cache, null, tiles, false, settingPkg); } } } } HashMap<String, DashboardCategory> categoryMap = new HashMap<>(); for (Tile tile : tiles) { DashboardCategory category = categoryMap.get(tile.category); if (category == null) { category = createCategory(context, tile.category, categoryDefinedInManifest); if (category == null) { Log.w(LOG_TAG, "Couldn't find category " + tile.category); continue; } categoryMap.put(category.key, category); } /*SPRD add for google sound settings*/ if (tile.intent.getComponent().getClassName().equals("com.android.settings.Settings$SoundSettingsActivity")) { if (isSupportGoogleAudio()) { category.addTile(tile); } else { continue; } } else if (tile.intent.getComponent().getClassName().equals("com.sprd.audioprofile.AudioProfileSettings")) { if (!isSupportGoogleAudio()) { tile.summary = context.getResources().getString(R.string.audio_profile_summary); category.addTile(tile); } else { continue; } } else if (tile.intent.getComponent().getClassName().equals("com.sprd.settings.timerpower.AlarmClock")) { tile.summary = context.getResources().getString(R.string.power_on_off); category.addTile(tile); } else { category.addTile(tile); } /*SPRD add for google sound settings end*/ //category.addTile(tile); } ArrayList<DashboardCategory> categories = new ArrayList<>(categoryMap.values()); for (DashboardCategory category : categories) { category.sortTiles(); } Collections.sort(categories, CATEGORY_COMPARATOR); if (DEBUG_TIMING) Log.d(LOG_TAG, "getCategories took " + (System.currentTimeMillis() - startTime) + " ms"); return categories; }
注意到标红的变量,实质上是通过解析AndroidManifest文件中的action字段来判断是否添加进category。
至此,Settings数据加载流程结束。