赞
踩
最近一直在看settings的问题,觉得不错,就研究了下,写出来方便以后查找问题,不用每次都去重新看,如有不对的地方,欢迎纠正。
在Android N 上Settings是带有侧拉菜单的,我们先从界面的角度大致看下Settings是怎么显示出来,然后再看下view对应的数据是如何加载而来的,先来看看设置的界面如下:
从图片可以看出主界面有点类似listview的感觉,只不过所有的item分为四类,依次为无线和网络、设备、个人、系统,接着我们就从源码的角度看下界面是如何显示出来的。Settings源码分为两个部分,分别为
“packages/apps/Settings”和“frameworks/base/packages/SettingsLib”,主界面对应的布局文件如下:
frameworks/base/packages/SettingsLib/res/layout/settings_with_drawer.xml
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/colorPrimaryDark">
<!-- 设置主界面 -->
<LinearLayout
android:id="@+id/content_parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle">
<Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:navigationContentDescription="@*android:string/action_bar_up_description"
android:theme="?android:attr/actionBarTheme"
style="?android:attr/toolbarStyle"
android:background="?android:attr/colorPrimary" />
</FrameLayout>
<FrameLayout
android:id="@+id/content_header_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/actionBarStyle" />
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:background="?android:attr/windowBackground" />
</LinearLayout>
<!-- 侧拉抽屉 -->
<ListView android:id="@+id/left_drawer"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="?android:attr/colorBackground" />
</android.support.v4.widget.DrawerLayout>
从布局文件可看出,整个布局为DrawerLayout,主界面为一个FrameLayout,还有个left_drawer对应侧边的侧滑栏,界面显示如下:
左边的侧滑栏比较简单就不罗嗦了,主要看下settings主界面是如何显示出来的,设置主界面入口为SettingsActivity.java是SettingsDrawerActivity.java的子类
packages/apps/Settings/src/com/android/settings/SettingsActivity.java
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
...
setContentView(mIsShowingDashboard ?
R.layout.settings_main_dashboard : R.layout.settings_main_prefs);加载主界面,为一个fragment
mContent = (ViewGroup) findViewById(R.id.main_content);
getFragmentManager().addOnBackStackChangedListener(this);
if (savedState != null) {
// We are restarting from a previous saved state; used that to initialize, instead
// of starting fresh.
mSearchMenuItemExpanded = savedState.getBoolean(SAVE_KEY_SEARCH_MENU_EXPANDED);
mSearchQuery = savedState.getString(SAVE_KEY_SEARCH_QUERY);
setTitleFromIntent(intent);
ArrayList<DashboardCategory> categories =
savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES);
if (categories != null) {
mCategories.clear();
mCategories.addAll(categories);
setTitleFromBackStack();
}
mDisplayHomeAsUpEnabled = savedState.getBoolean(SAVE_KEY_SHOW_HOME_AS_UP);
mDisplaySearch = savedState.getBoolean(SAVE_KEY_SHOW_SEARCH);
} else {
if (!mIsShowingDashboard) {
mDisplaySearch = false;
// UP will be shown only if it is a sub settings
if (mIsShortcut) {
mDisplayHomeAsUpEnabled = isSubSettings;
} else if (isSubSettings) {
mDisplayHomeAsUpEnabled = true;
} else {
mDisplayHomeAsUpEnabled = false;
}
setTitleFromIntent(intent);
Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
switchToFragment(initialFragmentName, initialArguments, true, false,
mInitialTitleResId, mInitialTitle, false);
} else {
// No UP affordance if we are displaying the main Dashboard
mDisplayHomeAsUpEnabled = false;
// Show Search affordance
mDisplaySearch = true;
mInitialTitleResId = R.string.dashboard_title;
// add argument to indicate which settings tab should be initially selected
final Bundle args = new Bundle();
final String extraName = DashboardContainerFragment.EXTRA_SELECT_SETTINGS_TAB;
args.putString(extraName, intent.getStringExtra(extraName));
switchToFragment(DashboardContainerFragment.class.getName(), args, false, false,mInitialTitleResId, mInitialTitle, false);切换到DashboardContainerFragment
}
}
...
}
在onCreate中加载了一个R.layout.settings_main_dashboard,布局文件很简单里面就一个FrameLayout,然后通过
switchToFragment,切换到DashboardContainerFragment,需要注意的是在调用switchToFragment切换到DashboardContainerFragment之前会检查Fragment是否有效,通过判断当前fragmentName是否为SettingsActivity.ENTRY_FRAGMENTS数组里定义的,否则会抛出IllegalArgumentException “Invalid fragment for this activity: “,到这里我们继续接着DashboardContainerFragment分析,DashboardContainerFragment的onCreateView如下:
packages/apps/Settings/src/com/android/settings/dashboard/DashboardContainerFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final View content = inflater.inflate(R.layout.dashboard_container, parent, false);加载一个自定义的viewpager
mViewPager = (RtlCompatibleViewPager) content.findViewById(R.id.pager);
mPagerAdapter = new DashboardViewPagerAdapter(getContext(),
getChildFragmentManager(), mViewPager);
mViewPager.setAdapter(mPagerAdapter);
mViewPager.addOnPageChangeListener(
new TabChangeListener((SettingsActivity) getActivity()));
// check if support tab needs to be selected
final String selectedTab = getArguments().
getString(EXTRA_SELECT_SETTINGS_TAB, ARG_SUMMARY_TAB);
if (TextUtils.equals(selectedTab, ARG_SUPPORT_TAB)) {
mViewPager.setCurrentItem(INDEX_SUPPORT_FRAGMENT);
} else {
mViewPager.setCurrentItem(INDEX_SUMMARY_FRAGMENT);
}
mHeaderView = inflater.inflate(R.layout.dashboard_container_header, parent, false);
((SlidingTabLayout) mHeaderView).setViewPager(mViewPager);
return content;
}
加载了一个RtlCompatibleViewPager,然后设置adapter为DashboardViewPagerAdapter,addOnPageChangeListener为TabChangeListener,DashboardViewPagerAdapter为FragmentPagerAdapter的子类,其实现如下:
packages/apps/Settings/src/com/android/settings/dashboard/DashboardContainerFragment.java
private static final class DashboardViewPagerAdapter extends FragmentPagerAdapter {
private final Context mContext;
private final SupportFeatureProvider mSupportFeatureProvider;
private final RtlCompatibleViewPager mViewPager;
public DashboardViewPagerAdapter(Context context, FragmentManager fragmentManager,
RtlCompatibleViewPager viewPager) {
super(fragmentManager);
mContext = context;
mSupportFeatureProvider =
FeatureFactory.getFactory(context).getSupportFeatureProvider(context);
mViewPager = viewPager;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case INDEX_SUMMARY_FRAGMENT:
return mContext.getString(R.string.page_tab_title_summary);
case INDEX_SUPPORT_FRAGMENT:
return mContext.getString(R.string.page_tab_title_support);
}
return super.getPageTitle(position);
}
@Override
public Fragment getItem(int position) {
switch (position) {返回DashboardSummary
case INDEX_SUMMARY_FRAGMENT:
return new DashboardSummary();
case INDEX_SUPPORT_FRAGMENT:
return new SupportFragment();
default:
throw new IllegalArgumentException(
String.format(
"Position %d does not map to a valid dashboard fragment",
position));
}
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
return super.instantiateItem(container,
mViewPager.getRtlAwareIndex(position));
}
@Override
public int getCount() {
return mSupportFeatureProvider == null ? 1 : 2;
}
}
mSupportFeatureProvider为null,默认只有一页即显示DashboardSummary,在DashboardSummary@onCreateView里填充了R.layout.dashboard,这个布局文件主要包含一个FocusRecyclerView
packages/apps/Settings/src/com/android/settings/dashboard/DashboardSummary.java
@Override
public void onViewCreated(View view, Bundle bundle) {
long startTime = System.currentTimeMillis();
mDashboard = (FocusRecyclerView) view.findViewById(R.id.dashboard_container);
mLayoutManager = new LinearLayoutManager(getContext());
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
if (bundle != null) {
int scrollPosition = bundle.getInt(EXTRA_SCROLL_POSITION);
mLayoutManager.scrollToPosition(scrollPosition);
}
mDashboard.setLayoutManager(mLayoutManager);
mDashboard.setHasFixedSize(true);
mDashboard.setListener(this);
mDashboard.addItemDecoration(new DashboardDecorator(getContext()));设置分割线
mAdapter = new DashboardAdapter(getContext(), mSuggestionParser, bundle,
mConditionManager.getConditions());
mDashboard.setAdapter(mAdapter);设置adapter
mSummaryLoader.setAdapter(mAdapter);
ConditionAdapterUtils.addDismiss(mDashboard);
if (DEBUG_TIMING) Log.d(TAG, "onViewCreated took "
+ (System.currentTimeMillis() - startTime) + " ms");
rebuildUI();
}
在这儿设置RecyclerView的setLayoutManager为垂直线性布局,设置adapter为DashboardAdapter以及rebuildUI,接下来主要看下DashboardAdapter,DashboardAdapter为RecyclerView.Adapter的子类,通过onCreateViewHolder和onBindViewHolder来创建和显示view
packages/apps/Settings/src/com/android/settings/dashboard/DashboardAdapter.java
@Override
public DashboardItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new DashboardItemHolder(LayoutInflater.from(parent.getContext()).inflate(
viewType, parent, false), (viewType == R.layout.dashboard_tile_switch));
}
@Override
public void onBindViewHolder(DashboardItemHolder holder, int position) {
switch (mTypes.get(position)) {
case R.layout.dashboard_category:对应类别
onBindCategory(holder, (DashboardCategory) mItems.get(position));
break;
case R.layout.dashboard_tile:对应每个子item
final Tile tile = (Tile) mItems.get(position);
onBindTile(holder, tile);
holder.itemView.setTag(tile);
holder.itemView.setOnClickListener(this);
break;
case R.layout.dashboard_tile_switch:
final Tile tileSitch = (Tile) mItems.get(position);
mLte4GEnablerHolder = holder;
onBindTile(holder, tileSitch);
holder.itemView.setOnClickListener(this);
mSw = (Switch) holder.itemView.findViewById(R.id.switchWidget);
mLte4GEnabler.setSwitch(mSw);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSw.setChecked(!mSw.isChecked());
set4GEnableSummary(mSw.isChecked());
}
});
updateLte4GEnabler();
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;
}
}
@Override
public int getItemViewType(int position) {
return mTypes.get(position);
}
@Override
public int getItemCount() {
return mIds.size();
}
在onBindViewHolder中通过type类型来创建不同的view类型并设置相应的点击事件R.layout.dashboard_category,对应着前面提到的四种类别(无线和网络、设备、个人、系统),R.layout.dashboard_tile对应着每个类别下的item(WLAN、蓝牙、流量使用情况等),每个item点击后,会调用 ((SettingsActivity) mContext).openTile((Tile) v.getTag())跳转到对应的界面,讲到这整个界面的显示就说的差不多了,接下来看下界面对应的数据是怎么来的。
在DashboardSummary@rebuildUI里会调用DashboardAdapter@setCategories的
packages/apps/Settings/src/com/android/settings/dashboard/DashboardAdapter.java
public void setCategories(List<DashboardCategory> categories) {
mCategories = categories;
// TODO: Better place for tinting?
TypedValue tintColor = new TypedValue();
mContext.getTheme().resolveAttribute(com.android.internal.R.attr.colorAccent,
tintColor, true);
for (int i = 0; i < categories.size(); i++) {
for (int j = 0; j < categories.get(i).tiles.size(); j++) {
Tile tile = categories.get(i).tiles.get(j);
if (!mContext.getPackageName().equals(
tile.intent.getComponent().getPackageName())) {
// If this drawable is coming from outside Settings, tint it to match the
// color.
tile.icon.setTint(tintColor.data);
}
}
}
recountItems(); //根据categories重新构建item,为DashboardAdapter提供数据
}
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(null, R.layout.dashboard_spacer, hasConditions && hasSuggestions, NS_SPACER);
countItem(null, R.layout.suggestion_header, hasSuggestions, NS_SPACER);
resetCount();
if (mSuggestions != null) {
int maxSuggestions = getDisplayableSuggestionCount();
for (int i = 0; i < mSuggestions.size(); i++) {
countItem(mSuggestions.get(i), R.layout.suggestion_tile, i < maxSuggestions,
NS_SUGGESTION);
}
}
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);
if (tile.intent.getComponent().getClassName().contains(LTE_4G_ACTIVITY)) {
countItem(tile, R.layout.dashboard_tile_switch, mIsShowingAll ||
ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
tile.intent.getComponent().getClassName()), NS_ITEMS);
} else {
countItem(tile, R.layout.dashboard_tile, mIsShowingAll
|| ArrayUtils.contains(DashboardSummary.INITIAL_ITEMS,
tile.intent.getComponent().getClassName()), NS_ITEMS);
}
}
}
}
notifyDataSetChanged();
}
那么DashboardAdapter@setCategories(List <DashboardCategory> categories) 传入的categories从何而来来呢
private void rebuildUI() {
if (!isAdded()) {
Log.w(TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added");
return;
}
List<DashboardCategory> categories =
((SettingsActivity) getActivity()).getDashboardCategories();
mAdapter.setCategories(categories);
// recheck to see if any suggestions have been changed.
new SuggestionLoader().execute();
}
在DashboardSummary@rebuildUI中我们知道,categories是调用SettingsActivity的方法获取的,getDashboardCategories这个方法是定义在SettingsActivity的父类SettingsDrawerActivity.java里定义的,如下:
frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
public List<DashboardCategory> getDashboardCategories() {
if (sDashboardCategories == null) {
sTileCache = new HashMap<>();
sConfigTracker = new InterestingConfigChanges();
// Apply initial current config.
sConfigTracker.applyNewConfig(getResources());
sDashboardCategories = TileUtils.getCategories(this, sTileCache);
}
return sDashboardCategories;
}
sDashboardCategories是通过TileUtils.getCategories赋值的,接着我们继续跟下这个方法
frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
public static List<DashboardCategory> getCategories(Context context,
HashMap<Pair<String, String>, 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.
//解析AndroidManifest.xml
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作为action去查找DashboardCategory,即(无线网络、设备、个人、系统)
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;
}
在这个方法中主要通过getTilesForIntent获取所有的Tile,其实主要就是通过PackageManager@queryIntentActivitiesAsUser通过传入的intnet解析AndroidManifest.xml配置的每项,解析设置中每个item(WLAN、蓝牙、流量使用情况、显示、通知…)
frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
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();
/*<action android:name="com.android.settings.action.SETTINGS" /> 根据action去查找所有匹配的项*/
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;
/*解析xml中的meta-data节点*/
Bundle metaData = activityInfo.metaData;
String categoryKey = defaultCategory;
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;
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);
}
}
}
对应解析的文件如下:
packages/apps/Settings/AndroidManifest.xml
<activity android:name="Settings$WifiSettingsActivity"
android:taskAffinity=""
android:label="@string/wifi_settings"
android:icon="@drawable/ic_settings_wireless"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter android:priority="1">
<action android:name="android.settings.WIFI_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<intent-filter android:priority="4">
<action android:name="com.android.settings.action.SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.wireless" />
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.wifi.WifiSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
解析并创建对应类别,如无线和网络,设备、个人、系统
frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
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 +" ,categoryKey="+categoryKey);
}
return category;
}
对应解析的xml文件
packages/apps/Settings/AndroidManifest.xml
<activity android:name=".Settings$WirelessSettings"
android:label="@string/header_category_wireless_networks">
<intent-filter android:priority="4">
<action android:name="com.android.settings.category.wireless" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
所有的data都是通过解析AndroidManifest.xml文件,然后把对应数据显示在界面的,讲到这就分解的差不多了,简单总结下:
1、设置对应的界面是SettingsActivity extends SettingsDrawerActivity,在SettingsActivity最后是加载了DashboardSummary,这个fragment加载了一个FocusRecyclerView,并设置adapter为DashboardAdapter
2、DashboardAdapter的数据是通过TileUtils@getCategories里的getTilesForAction和createCategory解析AndroidManifest.xml文件,返回List < DashboardCategory >供DashboardAdapter使用
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。