赞
踩
O版本的设置界面相对有N有了一些变化,O上面增加了顶级类别的菜单,而之前一些在一级菜单的则移动到了二级界面里面,
如"WIFI","移动网络"等之前是在一级界面的,而在O上则移动到了新菜单"网络和互联网"中,但是在数据在加载方面,并未做较大的变化.
(a)一级界面--顶级菜单的数据加载
在上一篇 <<android O版本 设置(Settings)模块总结--设置的启动界面选择>> 中有说到DashboardSummary是顶级菜单的容器,那么数据的获取和它也就有关系了:
DashboardSummary.java
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final Activity activity = getActivity();
- mDashboardFeatureProvider = FeatureFactory.getFactory(activity)
- .getDashboardFeatureProvider(activity);
- mSuggestionFeatureProvider = FeatureFactory.getFactory(activity)
- .getSuggestionFeatureProvider(activity);
-
- mSummaryLoader = new SummaryLoader(activity, CategoryKey.CATEGORY_HOMEPAGE);
-
- mConditionManager = ConditionManager.get(activity, false);
- getLifecycle().addObserver(mConditionManager);
- mSuggestionParser = new SuggestionParser(activity,
- activity.getSharedPreferences(SUGGESTIONS, 0), R.xml.suggestion_ordering);
- mSuggestionsChecks = new SuggestionsChecks(getContext());
- }
在DashboardSummary的onCreate函数中有获取的有两个很重要参数:mDashboardFeatureProvider,mSuggestionFeatureProvider.这两个是主要的数据提供者,mSuggestionFeatureProvider和mDashboardFeatureProvider的数据获取是有所不同的,这里就不再说明mSuggestionFeatureProvider了,重点说明下mDashboardFeatureProvider.
mDashboardFeatureProvider提供的数据是一级菜单如"电池","显示","网络和互联网"等,实现类为DashboardFeatureProviderImpl.java,而DashboardFeatureProviderImpl中的具体的数据是通过函数getTilesForCategory()从CategoryManager获取的.
- public DashboardFeatureProviderImpl(Context context) {
- mContext = context.getApplicationContext();
- mCategoryManager = CategoryManager.get(context, getExtraIntentAction());
- mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
- mPackageManager = context.getPackageManager();
- }
-
- @Override
- public DashboardCategory getTilesForCategory(String key) {
- return mCategoryManager.getTilesByCategory(mContext, key);
- }
CategoryManager是SettingsLib这个静态包中公共类,可以看一下:
- public static CategoryManager get(Context context, String action) {
- if (sInstance == null) {
- sInstance = new CategoryManager(context, action);
- }
- return sInstance;
- }
-
- CategoryManager(Context context, String action) {
- mTileByComponentCache = new ArrayMap<>();
- mCategoryByKeyMap = new ArrayMap<>();
- mInterestingConfigChanges = new InterestingConfigChanges();
- mInterestingConfigChanges.applyNewConfig(context.getResources());
- mExtraAction = action;
- }
可以看到CategoryManager是一个单例类型,这里就是真正的数据加载位置,加载是通过函数reloadAllCategories()调用tryInitCategories()获取的.
到这里为止,整个数据获取的流程已经清楚,但是数据加载是在哪里完成的呢,还要回到SettingsDrawerActivity中:
- SettingsDrawerActivity.java
- @Override
- protected void onResume() {
- super.onResume();
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- filter.addDataScheme("package");
- registerReceiver(mPackageReceiver, filter);
-
- new CategoriesUpdateTask().execute();
- final Intent intent = getIntent();
- if (intent != null && intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
- // Intent explicitly set to show menu.
- showMenuIcon();
- }
- }
在SettingsDrawerActivity中注册了安装应用状态变化的广播接收器等,但是这里还进行了一个异步操作:
new CategoriesUpdateTask().execute();
- private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
-
- private final CategoryManager mCategoryManager;
-
- public CategoriesUpdateTask() {
- mCategoryManager = CategoryManager.get(SettingsDrawerActivity.this);
- }
-
- @Override
- protected Void doInBackground(Void... params) {
- mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this, getSettingPkg());
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
- onCategoriesChanged();
- }
- }
在这个AsyncTask中,doInBackground()调用了CategoryManager的reloadAllCategories()函数,而onPostExecute则调用了接口CategoryListener的唯一方法onCategoriesChanged(),那么作为界面容器的DashboardSummary肯定重载了这个接口,实现了onCategoriesChanged()方法:
- DashboardSummary
- @Override
- public void onCategoriesChanged() {
- // Bypass rebuildUI() on the first call of onCategoriesChanged, since rebuildUI() happens
- // in onViewCreated as well when app starts. But, on the subsequent calls we need to
- // rebuildUI() because there might be some changes to suggestions and categories.
- if (isOnCategoriesChangedCalled) {
- rebuildUI();
- }
- isOnCategoriesChangedCalled = true;
- }
DashboardSummary在方法onCategoriesChanged()中进行了界面的刷新,这里先不了解,后边再说,继续研究数据加载.
mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this, getSettingPkg());
reloadAllCategories函数中调用了tryInitCategories(),此函数中是获取数据以及对数据的处理,来看下函数tryInitCategories:
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); } }
SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
- 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);
- }
- }
- }
- }
- //按照进行meta-data android:name="com.android.settings.category"进行分类
- 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);
- }
- category.addTile(tile);
- }
- //对分类进行排序
- ArrayList<DashboardCategory> categories = new ArrayList<>(categoryMap.values());
- for (DashboardCategory category : categories) {
- Collections.sort(category.tiles, TILE_COMPARATOR);
- }
- Collections.sort(categories, CATEGORY_COMPARATOR);
- if (DEBUG_TIMING) Log.d(LOG_TAG, "getCategories took "
- + (System.currentTimeMillis() - startTime) + " ms");
- return categories;
- }
在函数getCategories中,就逐个开始通过PackageManager获取包含有指定Action:
- private static final String SETTINGS_ACTION =
- "com.android.settings.action.SETTINGS";
-
- private static final String OPERATOR_SETTINGS =
- "com.android.settings.OPERATOR_APPLICATION_SETTING";
-
- private static final String MANUFACTURER_SETTINGS =
- "com.android.settings.MANUFACTURER_APPLICATION_SETTING";
- private static final String EXTRA_SETTINGS_ACTION =
-
- "com.android.settings.action.EXTRA_SETTINGS";
-
- private static void getTilesForAction(Context context,
- UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache,
- String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings,
- boolean usePriority, String settingPkg) {
- //填充Intent
- Intent intent = new Intent(action);
- if (requireSettings) {
- intent.setPackage(settingPkg);
- }
- getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
- usePriority, true);
- }
-
- public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
- Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
- boolean usePriority, boolean checkCategory) {
- PackageManager pm = context.getPackageManager();
- //通过PM 在已经安装的应用中获取指定Action的Activity信息.
- List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
- PackageManager.GET_META_DATA, user.getIdentifier());
-
- for (ResolveInfo resolved : results) {
- //此处是对非系统应用添加设置菜单做了限制的
- if (!resolved.system) {
- // Do not allow any app to add to settings, only system ones.
- continue;
- }
- ActivityInfo activityInfo = resolved.activityInfo;
- Bundle metaData = activityInfo.metaData;
- String categoryKey = defaultCategory;
-
- //通过meta-data android:name="com.android.settings.category"获取菜单分类.
- //例如:com.android.settings.category.ia.homepage就是在一级目录
- //例如:com.android.settings.category.ia.device显示在顶级菜单"设备链接"中
-
- // Load category
- if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
- && categoryKey == null) {
- Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
- + intent + " missing metadata "
- + (metaData == null ? "" : EXTRA_CATEGORY_KEY));
- continue;
- } else {
- categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
- }
-
- Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
- activityInfo.name);
- Tile tile = addedCache.get(key);
- if (tile == null) {
- tile = new Tile();
- tile.intent = new Intent().setClassName(
- activityInfo.packageName, activityInfo.name);
- tile.category = categoryKey;
- tile.priority = usePriority ? resolved.priority : 0;
- tile.metaData = activityInfo.metaData;
- //菜单的标题,图标,概要(summary),对应Activity的获取和赋值,这个可以自行分析下
- updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
- pm);
- if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
-
- addedCache.put(key, tile);
- }
- if (!tile.userHandle.contains(user)) {
- tile.userHandle.add(user);
- }
- if (!outTiles.contains(tile)) {
- outTiles.add(tile);
- }
- }
- }
使非设置的应用中添加设置顶级菜单,需要添加一下activity的相关的属性,下面例子可以参考一下:
<activity
android:name="Activity"
android:label="@string/app_name"
<intent-filter android:priority="6">
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.homepage" />
<meta-data
android:name="com.android.settings.icon"
android:resource="@drawable/ic_launcher_setting" />
</activity>
到了这里,数据加载流程基本上就总结完了,下面就要开始进行界面的加载了,要回到之前提到过的DashboardSummary的onCategoriesChanged()方法了.
(b)一级菜单界面加载,此处就比较简单了,是对View的绑定,我只把代码逻辑从头到位贴一下了 >.<
/src/com/android/settings/dashboard/DashboardSummary.java
- @Override
- public void onCategoriesChanged() {
- // Bypass rebuildUI() on the first call of onCategoriesChanged, since rebuildUI() happens
- // in onViewCreated as well when app starts. But, on the subsequent calls we need to
- // rebuildUI() because there might be some changes to suggestions and categories.
- if (isOnCategoriesChangedCalled) {
- rebuildUI();
- }
- isOnCategoriesChangedCalled = true;
- }
DashboardSummary.rebuildUI
- @VisibleForTesting
- void rebuildUI() {
- if (!mSuggestionFeatureProvider.isSuggestionEnabled(getContext())) {
- Log.d(TAG, "Suggestion feature is disabled, skipping suggestion entirely");
- updateCategoryAndSuggestion(null /* tiles */);
- } else {
- new SuggestionLoader().execute();
- // Set categories on their own if loading suggestions takes too long.
- mHandler.postDelayed(() -> {
- updateCategoryAndSuggestion(null /* tiles */);
- }, MAX_WAIT_MILLIS);
- }
- }
DashboardSummary.updateCategoryAndSuggestion
- @VisibleForTesting
- void updateCategoryAndSuggestion(List<Tile> suggestions) {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
-
- final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(
- CategoryKey.CATEGORY_HOMEPAGE);
- mSummaryLoader.updateSummaryToCache(category);
- if (suggestions != null) {
- mAdapter.setCategoriesAndSuggestions(category, suggestions);
- } else {
- mAdapter.setCategory(category);
- }
- }
./src/com/android/settings/dashboard/DashboardAdapter.java
- public void setCategoriesAndSuggestions(DashboardCategory category,
- List<Tile> suggestions) {
- tintIcons(category, suggestions);
-
- final DashboardData prevData = mDashboardData;
- mDashboardData = new DashboardData.Builder(prevData)
- .setSuggestions(suggestions.subList(0,
- Math.min(suggestions.size(), MAX_SUGGESTION_TO_SHOW)))
- .setCategory(category)
- .build();
- notifyDashboardDataChanged(prevData);
- List<Tile> shownSuggestions = null;
- final int mode = mDashboardData.getSuggestionConditionMode();
- if (mode == DashboardData.HEADER_MODE_DEFAULT) {
- shownSuggestions = suggestions.subList(0,
- Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT));
- } else if (mode != DashboardData.HEADER_MODE_COLLAPSED) {
- shownSuggestions = suggestions;
- }
- if (shownSuggestions != null) {
- for (Tile suggestion : shownSuggestions) {
- final String identifier = mSuggestionFeatureProvider.getSuggestionIdentifier(
- mContext, suggestion);
- mMetricsFeatureProvider.action(
- mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, identifier,
- getSuggestionTaggedData());
- mSuggestionsShownLogged.add(identifier);
- }
- }
- }
- public void setCategory(DashboardCategory category) {
- tintIcons(category, null);
- final DashboardData prevData = mDashboardData;
- Log.d(TAG, "adapter setCategory called");
- mDashboardData = new DashboardData.Builder(prevData)
- .setCategory(category)
- .build();
- notifyDashboardDataChanged(prevData);
- }
-
- @Override
- public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
- if (viewType == R.layout.suggestion_condition_header) {
- return new SuggestionAndConditionHeaderHolder(view);
- }
- if (viewType == R.layout.suggestion_condition_container) {
- return new SuggestionAndConditionContainerHolder(view);
- }
- return new DashboardItemHolder(view);
- }
-
- @Override
- public void onBindViewHolder(DashboardItemHolder holder, int position) {
- final int type = mDashboardData.getItemTypeByPosition(position);
- switch (type) {
- case R.layout.dashboard_tile:
- final Tile tile = (Tile) mDashboardData.getItemEntityByPosition(position);
- onBindTile(holder, tile);
- holder.itemView.setTag(tile);
- holder.itemView.setOnClickListener(mTileClickListener);
- break;
- case R.layout.suggestion_condition_container:
- onBindConditionAndSuggestion(
- (SuggestionAndConditionContainerHolder) holder, position);
- break;
- case R.layout.suggestion_condition_header:
- onBindSuggestionConditionHeader((SuggestionAndConditionHeaderHolder) holder,
- (SuggestionConditionHeaderData)
- mDashboardData.getItemEntityByPosition(position));
- break;
- case R.layout.suggestion_condition_footer:
- holder.itemView.setOnClickListener(v -> {
- mMetricsFeatureProvider.action(mContext,
- MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, false);
- DashboardData prevData = mDashboardData;
- mDashboardData = new DashboardData.Builder(prevData).setSuggestionConditionMode(
- DashboardData.HEADER_MODE_COLLAPSED).build();
- notifyDashboardDataChanged(prevData);
- mRecyclerView.scrollToPosition(SUGGESTION_CONDITION_HEADER_POSITION);
- });
- break;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。