随笔-107  评论-133  文章-4  trackbacks-0
转自:https://blog.csdn.net/A771642/article/details/70284335

Settings主界面加载时序图

(1)先看一下主界面布局

主界面对象介绍:

(1)主界面(除了Suggestion,condition)其他对象都在List<DashBoardCagtory> Categories里面

(2) Categories 有 4个对象。4个DashBoardCagtory的title值分别是 Wireless&networks,Device,Personal,System

(3)各个Cagtories都有List<Tile> tiles 是各个DashBoardCagtorytitle下面各个tile的集合

         组装这些对象是时序图中方法4,5,6,7,8。

4 getCategories

(1)调用5
(2)新建categoryMap集合
(3)遍历tiles,判断集合中是否有元素含有tile.category(当时我看见这个觉得google多此一举每次这个对象都是需要new但是我后来整        理manifest发现    含有相同category的tile很多。可以看我下面整理的manifest的表格)。如果没有就执行方法8
(4)将拥有相同属性category的tile加入到对象DashboardCategory category对象的list<tile>集合中
(5)将categoryMap的值赋值给List <DashboardCategory>cagtories以便执行排序算法
(6)遍历cagtories利用Collections函数和比较器TILE_COMPARATOR将category.tiles按照priority从大到小排序
(7)利用Collections函数和比较器CATEGORY_COMPARATOR将categories按照priority从大到小排序
public static List<DashboardCategory> getCategories(Context context,
            HashMap
<Pair<StringString>, Tile> cache) {
        final 
long startTime = System.currentTimeMillis();
        
boolean setup = Global.getInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0)
                !
= 0;
        ArrayList
<Tile> tiles = new ArrayList<>();
        UserManager userManager 
= UserManager.get(context);
        
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);
                getTilesForAction(context, user, OPERATOR_SETTINGS, cache,
                        OPERATOR_DEFAULT_CATEGORY, tiles, 
false);
                getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache,
                        MANUFACTURER_DEFAULT_CATEGORY, tiles, 
false);
            }
            
if (setup) {
                getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, 
null, tiles, false);
            }
        }
        HashMap
<String, DashboardCategory> categoryMap = new HashMap<>();
        
for (Tile tile : tiles) {
            DashboardCategory category 
= categoryMap.get(tile.category);
            
if (category == null) {
                category 
= createCategory(context, tile.category);
                
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;
    }

5 getTilesForAction

(1)组装Intent对象
(2)调用方法6
        private static void getTilesForAction(Context context,
                UserHandle user, 
String action, Map<Pair<StringString>, Tile> addedCache,
                
String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) {
            Intent intent 
= new Intent(action);
            
if (requireSettings) {
                intent.setPackage(SETTING_PKG);
            }
            getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
                    requireSettings, 
true);
        }

6 getTilesForIntent

(1)利用PM查询所有含有方法5生成的intent对象的ResolveInfo集合
(2)获取集合中每一个Acitvity manifest配置的meta标签name为SETTINGS_ACTION的value值
(3)把activity name 和package  生成Intent对象
(4)将2步骤的值赋值给Tile  category
(5)获取action为SETTINGS_ACTION的intent-filter的priority属性
(6)将解析meta-data标签的bundle数据赋值给Tile metaData
public static void getTilesForIntent(Context context, UserHandle user, Intent intent,
            Map
<Pair<StringString>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
            
boolean usePriority, boolean checkCategory) {
        PackageManager pm 
= context.getPackageManager();
        List
<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
                PackageManager.GET_META_DATA, user.getIdentifier());
        
for (ResolveInfo resolved : results) {
            
if (!resolved.system) {
                continue;
            }
            ActivityInfo activityInfo 
= resolved.activityInfo;
            Bundle metaData 
= activityInfo.metaData;
            
String categoryKey = defaultCategory;
            
if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
                    
&& categoryKey == null) {
                continue;
            } 
else {
                categoryKey 
= metaData.getString(EXTRA_CATEGORY_KEY);
            }
            Pair
<StringString> key = new Pair<StringString>(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;
                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);
            }
        }
    }

7 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
  private static boolean updateTileData(Context context, Tile tile,
            ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) {
        
if (applicationInfo.isSystemApp()) {
            
int icon = 0;
            CharSequence title 
= null;
            
String summary = null;
            try {
                Resources res 
= pm.getResourcesForApplication(
                        applicationInfo.packageName);
                Bundle metaData 
= activityInfo.metaData;
 
                
if (res != null && metaData != null) {
                    
if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
                        icon 
= metaData.getInt(META_DATA_PREFERENCE_ICON);
                    }
                    
if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
                        
if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) {
                            title 
= res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
                        } 
else {
                            title 
= metaData.getString(META_DATA_PREFERENCE_TITLE);
                        }
                    }
                    
if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
                        
if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) {
                            summary 
= res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
                        } 
else {
                            summary 
= metaData.getString(META_DATA_PREFERENCE_SUMMARY);
                        }
                    }
                }
            } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
                
if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e);
            }
            
if (TextUtils.isEmpty(title)) {
                title 
= activityInfo.loadLabel(pm).toString();
            }
            
if (icon == 0) {
                icon 
= activityInfo.icon;
            }
            tile.icon 
= Icon.createWithResource(activityInfo.packageName, icon);
            tile.title 
= title;
            tile.summary 
= summary;
            tile.intent 
= new Intent().setClassName(activityInfo.packageName,
                    activityInfo.name);
 
            return 
true;
        }
 
        return 
false;
    }

8 createCategory

(1)创建DashboardCategory对象
(2)利用PM查询所有含有Tile对象categoriyKey生成的intent对象的ResolveInfo集合
(3)把acitivity label值赋值给category title属性
(4)把解析intent-filter标签的priority值赋值给category属性
   private static DashboardCategory createCategory(Context context, String categoryKey) {
        DashboardCategory category 
= new DashboardCategory();
        category.key 
= categoryKey;
        PackageManager pm 
= context.getPackageManager();
        List
<ResolveInfo> results = pm.queryIntentActivities(new Intent(categoryKey), 0);
        
if (results.size() == 0) {
            return 
null;
        }
        
for (ResolveInfo resolved : results) {
            
if (!resolved.system) {
                
// Do not allow any app to add to settings, only system ones.
                continue;
            }
            category.title 
= resolved.activityInfo.loadLabel(pm);
            category.priority 
= SETTING_PKG.equals(
                    resolved.activityInfo.applicationInfo.packageName) ? resolved.priority : 
0;
            
if (DEBUG) Log.d(LOG_TAG, "Adding category " + category.title);
        }
 
        return category;
    }
Tile:
DashboardCategory:

16 new SummaryLoader

(1) 创建Handler对象
(2) 创建异步线程(大家可以去看一下线程优先级,做app还是挺有用处的)
(3) 遍历categories里面每一个DashboardCategory对象里面集合Tiles里面每一个tile对象
(4) 发送消息执行方法17
    public SummaryLoader(Activity activity, List<DashboardCategory> categories) {
        mHandler 
= new Handler();
        mWorkerThread 
= new HandlerThread("SummaryLoader", Process.THREAD_PRIORITY_BACKGROUND);
        mWorkerThread.start();
        mWorker 
= new Worker(mWorkerThread.getLooper());
        mActivity 
= activity;
        
for (int i = 0; i < categories.size(); i++) {
            List
<Tile> tiles = categories.get(i).tiles;
            
for (int j = 0; j < tiles.size(); j++) {
                Tile tile 
= tiles.get(j);
                mWorker.obtainMessage(Worker.MSG_GET_PROVIDER, tile).sendToTarget();
            }
        }
    }

17 makeProviderW

(1) 执行方法18

(2) 将方法18返回的SummaryProvider对象存入到mSummaryMap中

    private synchronized void makeProviderW(Tile tile) {
        SummaryProvider provider 
= getSummaryProvider(tile);
        
if (provider != null) {
            
if (DEBUG) Log.d(TAG, "Creating " + tile);
            mSummaryMap.put(provider, tile.intent.getComponent());
//provider和component建立关系
        }

18 getSummaryProvider(这代码让人大开眼界)

(1)获取title中的meataData变量
(2)将bundle数据metaData键为SettingsActivity.META_DATA_KEY_FRAGMENT的alue值赋值给clsName
(3)根据clsName反射创建class

(4)获取name为SUMMARY_PROVIDER_FACORY的变量Field

(5)拿到Field的值强制转换为SummaryProviderFactory对象
(6)返回反射类中SummaryProvider对象

private SummaryProvider getSummaryProvider(Tile tile) {
        
if (!mActivity.getPackageName().equals(tile.intent.getComponent().getPackageName())) {
            
// Not within Settings, can't load Summary directly.
            // TODO: Load summary indirectly.
            return 
null;
        }
        Bundle metaData 
= getMetaData(tile);
        
if (metaData == null) {
            
if (DEBUG) Log.d(TAG, "No metadata specified for " + tile.intent.getComponent());
            return 
null;
        }
        
String clsName = metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS);
        
if (clsName == null) {
            
if (DEBUG) Log.d(TAG, "No fragment specified for " + tile.intent.getComponent());
            return 
null;
        }
        try {
            Class
<?> cls = Class.forName(clsName);
            Field field 
= cls.getField(SUMMARY_PROVIDER_FACTORY);
            SummaryProviderFactory factory 
= (SummaryProviderFactory) field.get(null);
            return factory.createSummaryProvider(mActivity, this);
        } catch (ClassNotFoundException e) {
            
if (DEBUG) Log.d(TAG, "Couldn't find " + clsName, e);
        } catch (NoSuchFieldException e) {
            
if (DEBUG) Log.d(TAG, "Couldn't find " + SUMMARY_PROVIDER_FACTORY, e);
        } catch (ClassCastException e) {
            
if (DEBUG) Log.d(TAG, "Couldn't cast " + SUMMARY_PROVIDER_FACTORY, e);
        } catch (IllegalAccessException e) {
            
if (DEBUG) Log.d(TAG, "Couldn't get " + SUMMARY_PROVIDER_FACTORY, e);
        }
        return 
null;
    }

以NotificationApps.java为例

public class NotificationApps extends ManageApplications {
 
    
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
 
        
private final Context mContext;
        
private final SummaryLoader mLoader;
        
private final NotificationBackend mNotificationBackend;
 
        
private SummaryProvider(Context context, SummaryLoader loader) {
            mContext 
= context;
            mLoader 
= loader;
            mNotificationBackend 
= new NotificationBackend();
        }
 
        @Override
        
public void setListening(boolean listening) {
            
if (listening) {
                
new AppCounter(mContext) {
                    @Override
                    protected void onCountComplete(
int num) {
                        updateSummary(num);
                    }
 
                    @Override
                    protected 
boolean includeInCount(ApplicationInfo info) {
                        return mNotificationBackend.getNotificationsBanned(info.packageName,
                                info.uid);
                    }
                }.execute();
            }
        }
 
        
private void updateSummary(int count) {
            
if (count == 0) {
                mLoader.setSummary(this, mContext.getString(R.string.notification_summary_none));
            } 
else {
                mLoader.setSummary(this, mContext.getResources().getQuantityString(
                        R.plurals.notification_summary, count, count));
            }
        }
    }
 
    
public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
            
= new SummaryLoader.SummaryProviderFactory() {
        @Override
        
public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
                                                                   SummaryLoader summaryLoader) {
            return 
new SummaryProvider(activity, summaryLoader);
        }
    };
}

31 setListening

(1) 移除消息Worker.MSG_SET_LISTENING

(2) 发送消息Worker.MSG_SET_LISTENING 执行方法32

public void setListening(boolean listening) {
        
if (mListening == listening) return;
        mListening 
= listening;
        
// Unregister listeners immediately.
        
for (int i = 0; i < mReceivers.size(); i++) {
            mActivity.unregisterReceiver(mReceivers.valueAt(i));
        }
        mReceivers.clear();
        mWorker.removeMessages(Worker.MSG_SET_LISTENING);
        mWorker.obtainMessage(Worker.MSG_SET_LISTENING, listening ? 
1 : 00).sendToTarget();
    }

32 setListeningW(注意锁)

(1)遍历方法18生成的mSummaryMap键SummaryProvider

(2)将反射fragment类中静态内部类执行setListening方法

    private synchronized void setListeningW(boolean listening) {
        
if (mWorkerListening == listening) return;
        mWorkerListening 
= listening;
        
if (DEBUG) Log.d(TAG, "Listening " + listening);
        
for (SummaryProvider p : mSummaryMap.keySet()) {
            try {
                p.setListening(listening);
            } catch (Exception e) {
                
Log.d(TAG, "Problem in setListening", e);
            }
        }
    }

setSummary

当summary信息需要更新时,setSummary方法将会被调用:
    public void setSummary(SummaryProvider provider, final CharSequence summary) {
        final ComponentName component
= mSummaryMap.get(provider);
        mHandler.post(
new Runnable() {
            @Override
            
public void run() {
                
// Since tiles are not always cached (like on locale change for instance),
                
// we need to always get the latest one.
                Tile tile 
= mAdapter.getTile(component);
                
if (tile == null) return;
                
if (DEBUG) Log.d(TAG, "setSummary " + tile.title + " - " + summary);
                tile.summary 
= summary;
                mAdapter.notifyChanged(tile);
            }
        });
    }

28 recountItems

    private void recountItems() {
        reset();
        
boolean hasConditions = false;
        
for (int i = 0; mConditions != null && i < mConditions.size(); i++) {
            
boolean shouldShow = mConditions.get(i).shouldShow();
            hasConditions |
= shouldShow;
            countItem(mConditions.get(i), 
R.layout.condition_card, shouldShow, NS_CONDITION);
        }
boolean hasSuggestions = mSuggestions != null && mSuggestions.size() != 0;
        countItem(
nullR.layout.dashboard_spacer, hasConditions && hasSuggestions, NS_SPACER);
        countItem(
nullR.layout.suggestion_header , hasSuggestions, NS_SPACER);
        resetCount();

        if (mSuggestions != null) {
            
int maxSuggestions = mSuggestionMode == SUGGESTION_MODE_DEFAULT
                    ? Math.min(DEFAULT_SUGGESTION_COUNT, mSuggestions.size())
                    : mSuggestionMode 
== SUGGESTION_MODE_EXPANDED ? mSuggestions.size()
                    : 
0;
            
for (int i = 0; i < mSuggestions.size(); i++) {
                countItem(mSuggestions.get(i), 
R.layout.suggestion_tile, i < maxSuggestions,
                        NS_SUGGESTION);
            }
        }
        countItem(
nullR.layout.dashboard_spacertrue, NS_SPACER);
        resetCount();
        
for (int i = 0; mCategories != null && i < mCategories.size(); i++) {
            DashboardCategory category 
= mCategories.get(i);
            countItem(category, 
R.layout.dashboard_category, mIsShowingAll, NS_ITEMS);
            for (int j = 0; j < category.tiles.size(); j++) {
                Tile tile 
= category.tiles.get(j);
                countItem(tile, 
R.layout.dashboard_tile, mIsShowingAll
                        || ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
                        tile.intent.getComponent().getClassName()), NS_ITEMS);
            }
        }
        notifyDataSetChanged();
    }

29 countItem

    private void countItem(Object objectint type, boolean add, int nameSpace) {
        
if (add) {
            mItems.add(
object);
            mTypes.add(type);
            
// TODO: Counting namespaces for handling of suggestions/conds appearing/disappearing.
            mIds.add(
mId + nameSpace);
        }
        
mId++;
    }

onBindViewHolder

    public void onBindViewHolder(DashboardItemHolder holder, int position) { //sihid
        switch (mTypes.get(position)) {
            
case R.layout.dashboard_category:
                onBindCategory(holder, (DashboardCategory) mItems.get(position));
                break;
            
case R.layout.dashboard_tile:
                final Tile tile 
= (Tile) mItems.get(position);
                onBindTile(holder, tile);
                holder.itemView.setTag(tile);
                holder.itemView.setOnClickListener(this);
                break;
            
case R.layout.suggestion_header:
                onBindSuggestionHeader(holder);
                break;
            
case R.layout.suggestion_tile:
                final Tile suggestion 
= (Tile) mItems.get(position);
                onBindTile(holder, suggestion);
                holder.itemView.setOnClickListener(
new View.OnClickListener() {
                    @Override
                    
public void onClick(View v) {
                        MetricsLogger.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION,
                                DashboardAdapter.getSuggestionIdentifier(mContext, suggestion));
                        ((SettingsActivity) mContext).startSuggestion(suggestion.intent);
                    }
                });
                holder.itemView.findViewById(R.id.overflow).setOnClickListener(
                        
new View.OnClickListener() {
                            @Override
                            
public void onClick(View v) {
                                showRemoveOption(v, suggestion);
                            }
                        });
                break;
            
case R.layout.see_all:
                onBindSeeAll(holder);
                break;
            
case R.layout.condition_card:
                ConditionAdapterUtils.bindViews((Condition) mItems.get(position), holder,
                        mItems.get(position) 
== mExpandedCondition, this,
                        
new View.OnClickListener() {
                            @Override
                            
public void onClick(View v) {
                                onExpandClick(v);
                            }
                        });
                break;
        }
    }
到此界面第一次刷新完成。
posted on 2019-10-29 17:34 lfc 阅读(1446) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。