Android L Settings 简要分析
1.本文說明
??? 本文主要針對L平臺上Settings模塊正常啟動流程做一個簡要分析,并試著分析一下Settings下面Storage選項的實現過程。
?
?
2.Settings概覽
??? 在之前的KK平臺上Settings模塊的第一個Activity名字為Settings,其繼承的是PreferenceActivity,設置的每一個選項都是對應的一個Header對象,并且Header對象允許顯示switch控件,button控件,checkbox控件等。如下圖2.1,WLAN和藍牙上使用到了switch開關。但在L上面,WLAN和藍牙的這兩個開關已經去掉了,如圖2.2,在Settings模塊的首個頁面似乎就只是一個普通的Listview,那它用的還是不是Header呢?或者說取而代之的是什么呢?下一節詳細說明。
?
?
圖2.1 kkSettings首界面截圖
?
圖2.2 L Settings首界面
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?3 .L Settings 模塊首界面初始化流程
?
L Settings模塊首界面為Settings,繼承自SettingsActivity,SettingsActivity繼承自Activity。
?
首先看一下Settings.java代碼可以發現它沒有重寫任何SettingsActiviy的方法,也沒有增加任何自己的方法,唯獨增加了許多靜態內部類,如:
????/*
??? * 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 */?}
??? . . .
?
看注釋可以知道,這些子類是為了啟動特定獨立的Settings選項而創建的,例如在某個應用里需要設置無線那么只需要啟動 WirelessSettingsActivity 就可以了。
?
所以Settings模塊的啟動流程直接看SettingsActiviy就行了。
?
??? 3.1 SettingsActivity.onCreate方法
????
onCreate方法是Activity的生命周期第一步,看看 SettingsActivity在這里都做了些什么?
?
?????// Should happen before any call to getIntent()
???? getMetaData();
?
這個方法用來獲得Activity的額外數據mFragmentClass,如果可以獲得這個數據,那么下面會去顯示mFragmentClass對應的Activity。直接啟動Settings模塊不會獲得這個數據。
?
??? ?mIsShowingDashboard?= className.equals(Settings.class.getName());
這一步很重要,因為我們是從Settings這個Activity過來的,所以這里的 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);
這個判斷很重要但很明顯這時isSubSettings的值是fasle,暫時忽略。
?
??????? 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這個方法,可以知道這里是要切換DashboardSummary這個Fragment.
?
接下來就看看DashboardSummary是個什么玩意?
?
dashboard中文意思是儀表盤,這里是指DashboardSummary就是用來顯示Settings所有選項的。
在DashboardSummary的onCreateView里加載了這個布局文件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的選項視圖應該就是顯示在dashboard_container中了。
?
?
我們來看下面這張時序圖:
圖3.1 L Settings 初始化時序圖
?
?
?
?
?
DashboardSummary走完onCreateView方法后會走onResume,然后一路下來又會調到SettingsActivity的
?
loadCategoriesFromResource(R.xml.dashboard_categories, categories);
?
這一步是通過 R.xml.dashboard_categories來加載categories,這里的categorys為ArrayList<DashboardCategory>mCategories。接著來看看dashboard_categories.xml這個文件吧
:
<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>
?
根據這個文件我們可以知道了,所謂的dashboard就是Settings模塊首界面的一個抽象。而dashboard-categorys則是設置分類集合的抽象,而dashboard-category是分類的抽象,dashboard-tile就是分類下每個選項的抽象了。代碼中的List<DashboardCategory>對應dashboard-categorys, DashboardCategory對應dashboard-category,而dashboard-tile則對因代碼中的DashboardTile。
?
當加載完這些對象后SettingsActivity會將得到的?mCategories?返回給DashboardSummary來初始化Settings的設置選項。
?
?
下面這段代碼就是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);
??????? }
?
這段代碼我就不具體分析了,邏輯很簡單,遍歷categories這個列表來獲取DashboardCategory對象,將所有DashboardCategory對象和DashboardCategory對象中的DashboardTile對象轉化為視圖對象并添加到主視圖對象mDashboard中。
?
到這里SettingsActivity的onCreate方法就算結束了。總結一下,
????1.onCreate完成的任務是切換DashboardSmmary這個Fragment,然后從dashboard_categories.xml中讀取預先配置好的文件來初始化Settings的首界面視圖。
??? 2.L中舍棄了Header類,取而代之的是DashboardCategory和DashboardTile類。
?
?
?
?
4.0 L Settings模塊storage選項分析
?
?
當用戶點擊L settings模塊中的storage選項,程序的流程又是什么樣的,下面就具體看一下。
?
前面知道了配置文件中的dashboard-tile節點對應的是DashboardTile類,而DashboardTile對應的又是DashboardTileView這個視圖類,一個DashboardTileView的對象就是屏幕上的一個設置選項,當我們點擊storage選項時就會激發DashboardTileView的onClick響應:
?
????@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 這個變量,它所代表的就是上面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"
???????? />
?
這個節點中的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這個方法:
????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;
??? }
?
這里就是生成一個Intent嘛,這個Intent使用來啟動一個叫SubSettings的Activity的,而細心的同學也能發現SubSettings也是繼承自SettingsActivity的。然后給Intent加了一些額外的信息。
?
接著就是context.startActivity(intent);來啟動這個Activity了。
?
4.1storage 之 SubSettings 啟動流程
?
由于SubSettings也是繼承的SettingsActivity而且也幾乎沒做任何額外的擴充,這里分析SubSettings的啟動流程也可已直接分析SettingsActivity。
?
在SettingsActivity的onCreate方法中有這么一行:
?mIsShowingDashboard?= className.equals(Settings.class.getName());
因為這次我們啟動的是SubSettings,所以mIsShowingDashboard為false。所以代碼會走下面這段:
?
?????????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);
??????????? }
?
重點看switchToFragment這個方法:
?
????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;
??? }
?
很明顯,這個方法就是用來填充一個名字為fragmentName的Fragment的,這里的fragmentName是從最前面一路傳過來的,值為com.android.settings.deviceinfo.Memory 。我們可以轉移陣地了,從這一刻開始,界面會被Memory這個Fragment填充,而這個Fragment因該就是用來顯示storage使用情況的。
?
4.2????????????? Storage 之 Memory 流程分析
?
還是從Memory.java 的onCreate看起,這里第一個關鍵的方法是
?
????????addPreferencesFromResource(R.xml.device_info_memory);
?
由于此方法涉及到的代碼比較多,這里可以先看一下關于這個方法的時序圖:
?
?
?
圖4.1 addPreferencesFromResource方法相關時序圖
?
首先addPreferencesFromResource會從文件R.xml.device_info_memory?來加載Memory下的節點構成:
?
<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>
?
這個文件很簡單,只是單單指出了Memory下的根節點PregerenceScreen,看到上面的這句注釋也指出Preference Category會根據獲得的storage volumes(類似與分區或磁盤)被動態的添加PreferenceScreen下面。
?
設置完Memory的根節點PregerenceScreen后會有一個bindPreference的操作,這里會給Memory自帶的ListView設置OnItemClickListener和綁定PreferenceGroupAdapter適配器。在PreferenceGroupAdapter中獲得了PregerenceScreen對象的引用。
由于當前PreferenceScreen沒有任何子節點,暫時不對PreferenceGroupAdapte的實現做具體分析。
?
到此為止addPreferencesFromResource方法就算結束了,緊接著又來了一個有意思的方法:
?
??????? addCategory(StorageVolumePreferenceCategory.buildForInternal(context));
?
這個方法首先是獲得一個表示內部存儲的StorageVolumePreferenceCategory,接著調用 addCategory 將其添加到PreferenceScreen節點下:
?
????private?void?addCategory(StorageVolumePreferenceCategory category) {
????????mCategories.add(category);
??????? getPreferenceScreen().addPreference(category);
??????? category.init();
??? }
?
然后調用自身的init方法來初始化與Internal storage有關的信息。init方法里面的代碼就不貼了,比較長,主要就是獲得代表不同存儲信息的Preference,如總容量,可用空間,應用,圖片視頻,音頻,下載內容等,然后把這些Preference添加到StorageVolumePreferenceCategory節點下。
?
添加完內部存儲后,接下來的代碼回去遍歷其他存儲,這里默認只有內部存儲,添加其他存儲忽略。
?
看完了onCreate接下來看onResume,在這個方法中會調用StorageVolumePreferenceCategory的onResume方法來初始化里面每個preference的屬性值。時序圖如下:
圖4.2 StorageVolumePreferenceCategory的onResume方法時序圖
?
這里具體實現就不多講,StorageVolumePreferenceCategory是調用StorageMeasurement類來完成計算,再通過回調StorageVolumePreferenceCategory內部實現的接口MeasurementReceiver中的updateApproximate和updateDetails方法來分別更新總使用量和分類的具體占用量,完成這已系列計算后Memory的界面如下圖所示:
?
?
?
?
?
圖4.3 L Settings模塊storage界面
?
到此為止,storage的初始化就結束了,來總結一下storage的一個初始化流程:
???? 1.遍歷本地的storage volume并將其轉換為StorageVolumePreferenceCategory添加到PreferenceScreen。
???? 2.添加StorageVolumePreferenceCategory內部的各種類型的使用量StorageItemPreference。
???? 3.初始化StorageVolumePreferenceCategory內部的各個StorageItemPreference的屬性值。
原文地址:http://blog.csdn.net/will_captain/article/details/40901109
總結
以上是生活随笔為你收集整理的Android L Settings 简要分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Lollipop (5.
- 下一篇: Android Preference 须