Android L Settings 简要分析
1.本文說(shuō)明
??? 本文主要針對(duì)L平臺(tái)上Settings模塊正常啟動(dòng)流程做一個(gè)簡(jiǎn)要分析,并試著分析一下Settings下面Storage選項(xiàng)的實(shí)現(xiàn)過(guò)程。
?
?
2.Settings概覽
??? 在之前的KK平臺(tái)上Settings模塊的第一個(gè)Activity名字為Settings,其繼承的是PreferenceActivity,設(shè)置的每一個(gè)選項(xiàng)都是對(duì)應(yīng)的一個(gè)Header對(duì)象,并且Header對(duì)象允許顯示switch控件,button控件,checkbox控件等。如下圖2.1,WLAN和藍(lán)牙上使用到了switch開(kāi)關(guān)。但在L上面,WLAN和藍(lán)牙的這兩個(gè)開(kāi)關(guān)已經(jīng)去掉了,如圖2.2,在Settings模塊的首個(gè)頁(yè)面似乎就只是一個(gè)普通的Listview,那它用的還是不是Header呢?或者說(shuō)取而代之的是什么呢?下一節(jié)詳細(xì)說(shuō)明。
?
?
圖2.1 kkSettings首界面截圖
?
圖2.2 L Settings首界面
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?3 .L Settings 模塊首界面初始化流程
?
L Settings模塊首界面為Settings,繼承自SettingsActivity,SettingsActivity繼承自Activity。
?
首先看一下Settings.java代碼可以發(fā)現(xiàn)它沒(méi)有重寫任何SettingsActiviy的方法,也沒(méi)有增加任何自己的方法,唯獨(dú)增加了許多靜態(tài)內(nèi)部類,如:
????/*
??? * Settings subclasses for launching independently.
??? */
????public?static?class?BluetoothSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?WirelessSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?SimSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?TetherSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?VpnSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?DateTimeSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?StorageSettingsActivity?extends?SettingsActivity {?/* empty */?}
????public?static?class?WifiSettingsActivity?extends?SettingsActivity {?/* empty */?}
??? . . .
?
看注釋可以知道,這些子類是為了啟動(dòng)特定獨(dú)立的Settings選項(xiàng)而創(chuàng)建的,例如在某個(gè)應(yīng)用里需要設(shè)置無(wú)線那么只需要啟動(dòng) WirelessSettingsActivity 就可以了。
?
所以Settings模塊的啟動(dòng)流程直接看SettingsActiviy就行了。
?
??? 3.1 SettingsActivity.onCreate方法
????
onCreate方法是Activity的生命周期第一步,看看 SettingsActivity在這里都做了些什么?
?
?????// Should happen before any call to getIntent()
???? getMetaData();
?
這個(gè)方法用來(lái)獲得Activity的額外數(shù)據(jù)mFragmentClass,如果可以獲得這個(gè)數(shù)據(jù),那么下面會(huì)去顯示mFragmentClass對(duì)應(yīng)的Activity。直接啟動(dòng)Settings模塊不會(huì)獲得這個(gè)數(shù)據(jù)。
?
??? ?mIsShowingDashboard?= className.equals(Settings.class.getName());
這一步很重要,因?yàn)槲覀兪菑腟ettings這個(gè)Activity過(guò)來(lái)的,所以這里的 mIsShowingDashboard 為 true 。
?
????
?
???????
?
????? ?// This is a "Sub Settings" when:
????????// - this is a real SubSettings
????????// - or :settings:show_fragment_as_subsetting is passed to the Intent
????????final?boolean?isSubSettings = className.equals(SubSettings.class.getName()) ||
??????????????? intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING,?false);
這個(gè)判斷很重要但很明顯這時(shí)isSubSettings的值是fasle,暫時(shí)忽略。
?
??????? setContentView(mIsShowingDashboard??
??????????????? R.layout.settings_main_dashboard?: R.layout.settings_main_prefs);
?
前面知道這里的 mIsShowingDashboard為true,所以這里使用的布局文件為R.layout.settings_main_dashboard。settings_main_dashboard.xml文件如下:
?
<FrameLayout xmlns:Android="http://schemas.android.com/apk/res/android"
???????????? android:id="@+id/main_content"
???????????? android:layout_height="match_parent"
???????????? android:layout_width="match_parent"
???????????? android:background="@color/dashboard_background_color"
???????????? />
?
?
由于mIsShowingDashboard為true,直接走到下面這段
???????else?{
????????????????// No UP?affordance?if we are displaying the main?Dashboard
????????????????mDisplayHomeAsUpEnabled?=?false;
????????????????// Show Search?affordance
????????????????mDisplaySearch?=?true;
????????????????mInitialTitleResId?= R.string.dashboard_title;
??????????????? switchToFragment(DashboardSummary.class.getName(),?null,?false,?false,
????????????????????????mInitialTitleResId,?mInitialTitle,?false);
????????????? }
?
這里看到switchToFragment這個(gè)方法,可以知道這里是要切換DashboardSummary這個(gè)Fragment.
?
接下來(lái)就看看DashboardSummary是個(gè)什么玩意?
?
dashboard中文意思是儀表盤,這里是指DashboardSummary就是用來(lái)顯示Settings所有選項(xiàng)的。
在DashboardSummary的onCreateView里加載了這個(gè)布局文件R.layout.dashboard:
?
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
??? android:id="@+id/dashboard"
??? android:layout_width="match_parent"
??? android:layout_height="match_parent"
??? android:scrollbarStyle="outsideOverlay"
??? android:clipToPadding="false">
?
??????? <LinearLayout
??????????????? android:id="@+id/dashboard_container"
??????????????? android:layout_width="match_parent"
??????????????? android:layout_height="match_parent"
??????????????? android:layout_gravity="center_horizontal"
??????????????? android:paddingStart="@dimen/dashboard_padding_start"
??????????????? android:paddingEnd="@dimen/dashboard_padding_end"
??????????????? android:paddingTop="@dimen/dashboard_padding_top"
??????????????? android:paddingBottom="@dimen/dashboard_padding_bottom"
??????????????? android:orientation="vertical"
??????????????? />
?
</ScrollView>
?
看了上面的布局文件可以知道Settings的選項(xiàng)視圖應(yīng)該就是顯示在dashboard_container中了。
?
?
我們來(lái)看下面這張時(shí)序圖:
圖3.1 L Settings 初始化時(shí)序圖
?
?
?
?
?
DashboardSummary走完onCreateView方法后會(huì)走onResume,然后一路下來(lái)又會(huì)調(diào)到SettingsActivity的
?
loadCategoriesFromResource(R.xml.dashboard_categories, categories);
?
這一步是通過(guò) R.xml.dashboard_categories來(lái)加載categories,這里的categorys為ArrayList<DashboardCategory>mCategories。接著來(lái)看看dashboard_categories.xml這個(gè)文件吧
:
<dashboard-categories
??????? xmlns:android="http://schemas.android.com/apk/res/android">
?
??? <!-- WIRELESS and NETWORKS -->
??? <dashboard-category
??????????? android:id="@+id/wireless_section"
??????????? android:title="@string/header_category_wireless_networks" >
?
??????? <!-- Wifi -->
??????? <dashboard-tile
??????????????? android:id="@+id/wifi_settings"
??????????????? android:title="@string/wifi_settings_title"
??????????????? android:fragment="com.android.settings.wifi.WifiSettings"
?????????????? ?android:icon="@drawable/ic_settings_wireless"
??????????????? />
?
??????? <!-- Bluetooth -->
??????? <dashboard-tile
??????????????? android:id="@+id/bluetooth_settings"
??????????????? android:title="@string/bluetooth_settings_title"
??????????????? android:fragment="com.android.settings.bluetooth.BluetoothSettings"
??????????????? android:icon="@drawable/ic_settings_bluetooth2"
??????????????? />
?
??????? <!-- SIM Cards -->
??????? <dashboard-tile
??????????????? android:id="@+id/sim_settings"
??????????????? android:title="@string/sim_settings_title"
??????????????? android:fragment="com.android.settings.sim.SimSettings"
??????????????? android:icon="@drawable/ic_sim_sd"
??????????????? />
?
??????? <!-- Data Usage -->
??????? <dashboard-tile
? ??????????????android:id="@+id/data_usage_settings"
??????????????? android:title="@string/data_usage_summary_title"
??????????????? android:fragment="com.android.settings.DataUsageSummary"
??????????????? android:icon="@drawable/ic_settings_data_usage"
??????????????? />
?
??????? <!-- Operator hook -->
??????? <dashboard-tile
??????????????? android:id="@+id/operator_settings"
??????????????? android:fragment="com.android.settings.WirelessSettings" >
??????????? <intent android:action="com.android.settings.OPERATOR_APPLICATION_SETTING" />
??????? </dashboard-tile>
?
??????? <!-- Other wireless and network controls -->
??????? <dashboard-tile
??????????????? android:id="@+id/wireless_settings"
??????????????? android:title="@string/radio_controls_title"
?? ?????????????android:fragment="com.android.settings.WirelessSettings"
??????????????? android:icon="@drawable/ic_settings_more"
??????????????? />
?
??? </dashboard-category>
?
??? <!-- DEVICE -->
??? <dashboard-category
??????????? android:id="@+id/device_section"
??????????? android:title="@string/header_category_device" >
?
??????? <!-- Home -->
??????? <dashboard-tile
??????????????? android:id="@+id/home_settings"
??????????????? android:title="@string/home_settings"
??????????????? android:fragment="com.android.settings.HomeSettings"
??????????????? android:icon="@drawable/ic_settings_home"
??????????????? />
?
??????? <!-- Display -->
??????? <dashboard-tile
??????????????? android:id="@+id/display_settings"
??????????????? android:title="@string/display_settings"
??????????????? android:fragment="com.android.settings.DisplaySettings"
??????????????? android:icon="@drawable/ic_settings_display"
??????????????? />
?
??????? <!-- Notifications -->
??????? <dashboard-tile
??????????????? android:id="@+id/notification_settings"
??????????????? android:title="@string/notification_settings"
??????????????? android:fragment="com.android.settings.notification.NotificationSettings"
??????????????? android:icon="@drawable/ic_settings_notifications"
??????????????? />
?
??????? <!-- Storage -->
??????? <dashboard-tile
??????????????? android:id="@+id/storage_settings"
??????????????? android:title="@string/storage_settings"
??????????????? android:fragment="com.android.settings.deviceinfo.Memory"
??????????????? android:icon="@drawable/ic_settings_storage"
??????????????? />
?
??????? <!-- Battery -->
??????? <dashboard-tile
??????????????? android:id="@+id/battery_settings"
??????????????? android:title="@string/power_usage_summary_title"
???????? ???????android:fragment="com.android.settings.fuelgauge.PowerUsageSummary"
??????????????? android:icon="@drawable/ic_settings_battery"
??????????????? />
?
??????? <!-- Application Settings -->
??????? <dashboard-tile
??????????????? android:id="@+id/application_settings"
??????????????? android:title="@string/applications_settings"
??????????????? android:fragment="com.android.settings.applications.ManageApplications"
??????????????? android:icon="@drawable/ic_settings_applications"
??????????????? />
?
?? ?????<!-- Manage users -->
??????? <dashboard-tile
??????????????? android:id="@+id/user_settings"
??????????????? android:title="@string/user_settings_title"
??????????????? android:fragment="com.android.settings.users.UserSettings"
??????????????? android:icon="@drawable/ic_settings_multiuser"
??????????????? />
?
??????? <!-- Manage NFC payment apps -->
??????? <dashboard-tile
??????????????? android:id="@+id/nfc_payment_settings"
??????????????? android:title="@string/nfc_payment_settings_title"
? ??????????????android:fragment="com.android.settings.nfc.PaymentSettings"
??????????????? android:icon="@drawable/ic_settings_nfc_payment"
??????????????? />
?
??????? <!-- Manufacturer hook -->
??????? <dashboard-tile
??????????????? android:id="@+id/manufacturer_settings"
??????????????? android:fragment="com.android.settings.WirelessSettings">
??????????? <intent android:action="com.android.settings.MANUFACTURER_APPLICATION_SETTING" />
??????? </dashboard-tile>
?
??? </dashboard-category>
?
??? <!-- PERSONAL -->
??? <dashboard-category
??????????? android:id="@+id/personal_section"
??????????? android:title="@string/header_category_personal" >
?
??????? <!-- Location -->
??????? <dashboard-tile
??????????????? android:id="@+id/location_settings"
??????????????? android:title="@string/location_settings_title"
??????????????? android:fragment="com.android.settings.location.LocationSettings"
??????????????? android:icon="@drawable/ic_settings_location"
??????????????? />
?
??????? <!-- Security -->
??????? <dashboard-tile
??????????????? android:id="@+id/security_settings"
??????????????? android:title="@string/security_settings_title"
??????????????? android:fragment="com.android.settings.SecuritySettings"
??????????????? android:icon="@drawable/ic_settings_security"
??????????????? />
?
??????? <!-- Account -->
??????? <dashboard-tile
??????????????? android:id="@+id/account_settings"
??????????????? android:title="@string/account_settings_title"
??????????????? android:fragment="com.android.settings.accounts.AccountSettings"
??????????????? android:icon="@drawable/ic_settings_accounts"
??????????????? />
?
??????? <!-- Language -->
??????? <dashboard-tile
??????????????? android:id="@+id/language_settings"
??????????????? android:title="@string/language_settings"
??????????????? android:fragment="com.android.settings.inputmethod.InputMethodAndLanguageSettings"
??????????????? android:icon="@drawable/ic_settings_language"
??????????????? />
?
??????? <!-- Backup and reset -->
??????? <dashboard-tile
??????????????? android:id="@+id/privacy_settings"
??????????????? android:title="@string/privacy_settings"
??????????????? android:fragment="com.android.settings.PrivacySettings"
??????????????? android:icon="@drawable/ic_settings_backup"
??????????????? />
?
??? </dashboard-category>
?
??? <!-- SYSTEM -->
??? <dashboard-category
??????? android:id="@+id/system_section"
??????? android:title="@string/header_category_system" >
?
??????? <!-- Date & Time -->
??????? <dashboard-tile
??????????????? android:id="@+id/date_time_settings"
??????????????? android:title="@string/date_and_time_settings_title"
??????????????? android:fragment="com.android.settings.DateTimeSettings"
??????????????? android:icon="@drawable/ic_settings_date_time"
??????????????? />
?
?????? ?<!-- Accessibility feedback -->
??????? <dashboard-tile
??????????????? android:id="@+id/accessibility_settings"
??????????????? android:title="@string/accessibility_settings"
??????????????? android:fragment="com.android.settings.accessibility.AccessibilitySettings"
??????????????? android:icon="@drawable/ic_settings_accessibility"
??????????????? />
?
??????? <!-- Print -->
??????? <dashboard-tile
??????????????? android:id="@+id/print_settings"
?????????????? ?android:title="@string/print_settings"
??????????????? android:fragment="com.android.settings.print.PrintSettingsFragment"
??????????????? android:icon="@drawable/ic_settings_print"
??????????????? />
?
??????? <!-- Development -->
??????? <dashboard-tile
??????????????? android:id="@+id/development_settings"
??????????????? android:title="@string/development_settings_title"
??????????????? android:fragment="com.android.settings.DevelopmentSettings"
??????????????? android:icon="@drawable/ic_settings_development"
??????????????? />
?
??????? <!-- About Device -->
??????? <dashboard-tile
??????????????? android:id="@+id/about_settings"
??????????????? android:title="@string/about_settings"
??????????????? android:fragment="com.android.settings.DeviceInfoSettings"
??????????????? android:icon="@drawable/ic_settings_about"
??????????????? />
?
??? </dashboard-category>
?
</dashboard-categories>
?
根據(jù)這個(gè)文件我們可以知道了,所謂的dashboard就是Settings模塊首界面的一個(gè)抽象。而dashboard-categorys則是設(shè)置分類集合的抽象,而dashboard-category是分類的抽象,dashboard-tile就是分類下每個(gè)選項(xiàng)的抽象了。代碼中的List<DashboardCategory>對(duì)應(yīng)dashboard-categorys, DashboardCategory對(duì)應(yīng)dashboard-category,而dashboard-tile則對(duì)因代碼中的DashboardTile。
?
當(dāng)加載完這些對(duì)象后SettingsActivity會(huì)將得到的?mCategories?返回給DashboardSummary來(lái)初始化Settings的設(shè)置選項(xiàng)。
?
?
下面這段代碼就是DashboardSummary.rebuildUI()中完成界面的初始化
?
????????long?start = System.currentTimeMillis();
????????final?Resources?res =?getResources();
?
????????mDashboard.removeAllViews();
?
??????? List<DashboardCategory> categories =
??????????????? ((SettingsActivity) context).getDashboardCategories(true);
?
????????final?int?count = categories.size();
????????for?(int?n = 0; n < count; n++) {
??????????? DashboardCategory category = categories.get(n);
?
??????????? View categoryView =?mLayoutInflater.inflate(R.layout.dashboard_category,?mDashboard,
????????????????????false);
?
??????????? TextView categoryLabel = (TextView) categoryView.findViewById(R.id.category_title);
??????????? categoryLabel.setText(category.getTitle(res));
?
??????????? ViewGroup categoryContent =
??????????????????? (ViewGroup) categoryView.findViewById(R.id.category_content);
?
????????????final?int?tilesCount = category.getTilesCount();
????????????for?(int?i = 0; i < tilesCount; i++) {
??????????????? DashboardTile tile = category.getTile(i);
?
??????????????? DashboardTileView tileView =?new?DashboardTileView(context);
??????????????? updateTileView(context, res, tile, tileView.getImageView(),
??????????????????????? tileView.getTitleTextView(), tileView.getStatusTextView());
?
??????????????? tileView.setTile(tile);
?
??????????????? categoryContent.addView(tileView);
??????????? }
?
????????????// Add the category
????????????mDashboard.addView(categoryView);
??????? }
?
這段代碼我就不具體分析了,邏輯很簡(jiǎn)單,遍歷categories這個(gè)列表來(lái)獲取DashboardCategory對(duì)象,將所有DashboardCategory對(duì)象和DashboardCategory對(duì)象中的DashboardTile對(duì)象轉(zhuǎn)化為視圖對(duì)象并添加到主視圖對(duì)象mDashboard中。
?
到這里SettingsActivity的onCreate方法就算結(jié)束了。總結(jié)一下,
????1.onCreate完成的任務(wù)是切換DashboardSmmary這個(gè)Fragment,然后從dashboard_categories.xml中讀取預(yù)先配置好的文件來(lái)初始化Settings的首界面視圖。
??? 2.L中舍棄了Header類,取而代之的是DashboardCategory和DashboardTile類。
?
?
?
?
4.0 L Settings模塊storage選項(xiàng)分析
?
?
當(dāng)用戶點(diǎn)擊L settings模塊中的storage選項(xiàng),程序的流程又是什么樣的,下面就具體看一下。
?
前面知道了配置文件中的dashboard-tile節(jié)點(diǎn)對(duì)應(yīng)的是DashboardTile類,而DashboardTile對(duì)應(yīng)的又是DashboardTileView這個(gè)視圖類,一個(gè)DashboardTileView的對(duì)象就是屏幕上的一個(gè)設(shè)置選項(xiàng),當(dāng)我們點(diǎn)擊storage選項(xiàng)時(shí)就會(huì)激發(fā)DashboardTileView的onClick響應(yīng):
?
????@Override
????public?void?onClick(View v) {
????????if?(mTile.fragment?!=?null) {
??????????? Utils.startWithFragment(getContext(),?mTile.fragment,?????????mTile.fragmentArguments,?null, 0,
????????????????????mTile.titleRes,?mTile.getTitle(getResources()));
??????? }?else?if?(mTile.intent?!=?null) {
??????????? getContext().startActivity(mTile.intent);
??????? }
??? }
?
這里看到 mTile.fragment 這個(gè)變量,它所代表的就是上面dashboard_categories.xml文件下的
??????? <!-- Storage -->
??????? <dashboard-tile
??????????????? android:id="@+id/storage_settings"
??????????????? android:title="@string/storage_settings"
??????????????? android:fragment="com.android.settings.deviceinfo.Memory"
??????????????? android:icon="@drawable/ic_settings_storage"
???????? />
?
這個(gè)節(jié)點(diǎn)中的android:fragment="com.android.settings.deviceinfo.Memory"?屬性。
?
接著一路跟蹤Utils.startWithFragment方法,走到下面這段代碼:
?
????public?static?void?startWithFragment(Context context, String fragmentName, Bundle args,
??????????? Fragment resultTo,?int?resultRequestCode,?int?titleResId, CharSequence title,
????????????boolean?isShortcut) {
??????? Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, titleResId,
??????????????? title, isShortcut);
????????if?(resultTo ==?null) {
??????????? context.startActivity(intent);
??????? }?else?{
??????????? resultTo.startActivityForResult(intent, resultRequestCode);
??????? }
??? }
?
我們先看onBuildStartFragmentIntent這個(gè)方法:
????public?static?Intent onBuildStartFragmentIntent(Context context, String fragmentName,
??????????? Bundle args,?int?titleResId, CharSequence title,?boolean?isShortcut) {
??????? Intent intent =?new?Intent(Intent.ACTION_MAIN);
??????? intent.setClass(context, SubSettings.class);
??????? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, fragmentName);
??????? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
??????? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId);
??? ????intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
??????? intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut);
????????return?intent;
??? }
?
這里就是生成一個(gè)Intent嘛,這個(gè)Intent使用來(lái)啟動(dòng)一個(gè)叫SubSettings的Activity的,而細(xì)心的同學(xué)也能發(fā)現(xiàn)SubSettings也是繼承自SettingsActivity的。然后給Intent加了一些額外的信息。
?
接著就是context.startActivity(intent);來(lái)啟動(dòng)這個(gè)Activity了。
?
4.1storage 之 SubSettings 啟動(dòng)流程
?
由于SubSettings也是繼承的SettingsActivity而且也幾乎沒(méi)做任何額外的擴(kuò)充,這里分析SubSettings的啟動(dòng)流程也可已直接分析SettingsActivity。
?
在SettingsActivity的onCreate方法中有這么一行:
?mIsShowingDashboard?= className.equals(Settings.class.getName());
因?yàn)檫@次我們啟動(dòng)的是SubSettings,所以mIsShowingDashboard為false。所以代碼會(huì)走下面這段:
?
?????????if?(!mIsShowingDashboard) {
????????????????// Search is shown we are launched thru a Settings "shortcut". UP will be shown
????????????????// only if it is a sub settings
????????????????if?(mIsShortcut) {
????????????????????mDisplayHomeAsUpEnabled?= isSubSettings;
????????????????????mDisplaySearch?=?false;
??????????????? }?else?if?(isSubSettings) {
????????????????????mDisplayHomeAsUpEnabled?=?true;
????????????????????mDisplaySearch?=?true;
??????????????? }?else?{
????????????????????mDisplayHomeAsUpEnabled?=?false;
????????????????????mDisplaySearch?=?false;
??????????????? }
??????????????? setTitleFromIntent(intent);
?
??????????????? Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
??????????????? switchToFragment(initialFragmentName, initialArguments,?true,?false,
????????????????????????mInitialTitleResId,?mInitialTitle,?false);
??????????? }
?
重點(diǎn)看switchToFragment這個(gè)方法:
?
????private?Fragment switchToFragment(String fragmentName, Bundle args,?boolean?validate,
????????????boolean?addToBackStack,?int?titleResId, CharSequence title,?boolean?withTransition) {
?? ?????if?(validate && !isValidFragment(fragmentName)) {
????????????throw?new?IllegalArgumentException("Invalid fragment for this activity: "
??????????????????? + fragmentName);
??????? }
??????? Fragment f = Fragment.instantiate(this, fragmentName, args);
??????? FragmentTransaction transaction = getFragmentManager().beginTransaction();
??????? transaction.replace(R.id.main_content, f);
????????if?(withTransition) {
??????????? TransitionManager.beginDelayedTransition(mContent);
??????? }
????????if?(addToBackStack) {
??????????? transaction.addToBackStack(SettingsActivity.BACK_STACK_PREFS);
??????? }
????????if?(titleResId > 0) {
??????????? transaction.setBreadCrumbTitle(titleResId);
??????? }?else?if?(title !=?null) {
??????????? transaction.setBreadCrumbTitle(title);
??????? }
??????? transaction.commitAllowingStateLoss();
??????? getFragmentManager().executePendingTransactions();
????????return?f;
??? }
?
很明顯,這個(gè)方法就是用來(lái)填充一個(gè)名字為fragmentName的Fragment的,這里的fragmentName是從最前面一路傳過(guò)來(lái)的,值為com.android.settings.deviceinfo.Memory 。我們可以轉(zhuǎn)移陣地了,從這一刻開(kāi)始,界面會(huì)被Memory這個(gè)Fragment填充,而這個(gè)Fragment因該就是用來(lái)顯示storage使用情況的。
?
4.2????????????? Storage 之 Memory 流程分析
?
還是從Memory.java 的onCreate看起,這里第一個(gè)關(guān)鍵的方法是
?
????????addPreferencesFromResource(R.xml.device_info_memory);
?
由于此方法涉及到的代碼比較多,這里可以先看一下關(guān)于這個(gè)方法的時(shí)序圖:
?
?
?
圖4.1 addPreferencesFromResource方法相關(guān)時(shí)序圖
?
首先addPreferencesFromResource會(huì)從文件R.xml.device_info_memory?來(lái)加載Memory下的節(jié)點(diǎn)構(gòu)成:
?
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
????????????????? xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
??????? android:title="@string/storage_settings"
??????? settings:keywords="@string/keywords_storage">
?
<!-- Preference categories are dynamically created based on the list of available storage volumes -->
?
</PreferenceScreen>
?
這個(gè)文件很簡(jiǎn)單,只是單單指出了Memory下的根節(jié)點(diǎn)PregerenceScreen,看到上面的這句注釋也指出Preference Category會(huì)根據(jù)獲得的storage volumes(類似與分區(qū)或磁盤)被動(dòng)態(tài)的添加PreferenceScreen下面。
?
設(shè)置完Memory的根節(jié)點(diǎn)PregerenceScreen后會(huì)有一個(gè)bindPreference的操作,這里會(huì)給Memory自帶的ListView設(shè)置OnItemClickListener和綁定PreferenceGroupAdapter適配器。在PreferenceGroupAdapter中獲得了PregerenceScreen對(duì)象的引用。
由于當(dāng)前PreferenceScreen沒(méi)有任何子節(jié)點(diǎn),暫時(shí)不對(duì)PreferenceGroupAdapte的實(shí)現(xiàn)做具體分析。
?
到此為止addPreferencesFromResource方法就算結(jié)束了,緊接著又來(lái)了一個(gè)有意思的方法:
?
??????? addCategory(StorageVolumePreferenceCategory.buildForInternal(context));
?
這個(gè)方法首先是獲得一個(gè)表示內(nèi)部存儲(chǔ)的StorageVolumePreferenceCategory,接著調(diào)用 addCategory 將其添加到PreferenceScreen節(jié)點(diǎn)下:
?
????private?void?addCategory(StorageVolumePreferenceCategory category) {
????????mCategories.add(category);
??????? getPreferenceScreen().addPreference(category);
??????? category.init();
??? }
?
然后調(diào)用自身的init方法來(lái)初始化與Internal storage有關(guān)的信息。init方法里面的代碼就不貼了,比較長(zhǎng),主要就是獲得代表不同存儲(chǔ)信息的Preference,如總?cè)萘?#xff0c;可用空間,應(yīng)用,圖片視頻,音頻,下載內(nèi)容等,然后把這些Preference添加到StorageVolumePreferenceCategory節(jié)點(diǎn)下。
?
添加完內(nèi)部存儲(chǔ)后,接下來(lái)的代碼回去遍歷其他存儲(chǔ),這里默認(rèn)只有內(nèi)部存儲(chǔ),添加其他存儲(chǔ)忽略。
?
看完了onCreate接下來(lái)看onResume,在這個(gè)方法中會(huì)調(diào)用StorageVolumePreferenceCategory的onResume方法來(lái)初始化里面每個(gè)preference的屬性值。時(shí)序圖如下:
圖4.2 StorageVolumePreferenceCategory的onResume方法時(shí)序圖
?
這里具體實(shí)現(xiàn)就不多講,StorageVolumePreferenceCategory是調(diào)用StorageMeasurement類來(lái)完成計(jì)算,再通過(guò)回調(diào)StorageVolumePreferenceCategory內(nèi)部實(shí)現(xiàn)的接口MeasurementReceiver中的updateApproximate和updateDetails方法來(lái)分別更新總使用量和分類的具體占用量,完成這已系列計(jì)算后Memory的界面如下圖所示:
?
?
?
?
?
圖4.3 L Settings模塊storage界面
?
到此為止,storage的初始化就結(jié)束了,來(lái)總結(jié)一下storage的一個(gè)初始化流程:
???? 1.遍歷本地的storage volume并將其轉(zhuǎn)換為StorageVolumePreferenceCategory添加到PreferenceScreen。
???? 2.添加StorageVolumePreferenceCategory內(nèi)部的各種類型的使用量StorageItemPreference。
???? 3.初始化StorageVolumePreferenceCategory內(nèi)部的各個(gè)StorageItemPreference的屬性值。
原文地址:http://blog.csdn.net/will_captain/article/details/40901109
總結(jié)
以上是生活随笔為你收集整理的Android L Settings 简要分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android Lollipop (5.
- 下一篇: Android Preference 须