Android 5.1 Settings源码简要分析
概述:
先聲明:本人工作快兩年了,仍是菜鳥級別的,慚愧啊!以前遇到好多知識點都沒有記錄下來,感覺挺可惜的,現在有機會接觸Android 源碼。我們一個Android組的搞Setting,我覺得是得寫得東西,畢竟才接觸,現在只能看一段時間代碼,就先記錄下一些收獲吧,說多了就是淚~本文主要針對L平臺上Settings模塊正常啟動流程做一個簡要分析,并試著分析一下Settings下面某選項的實現。
Setting 簡介
在之前的KK平臺上Settings模塊的第一個Activity名字為Settings,其繼承的是PreferenceActivity,設置的每一個選項都是對應的一個Header對象,并且Header對象允許顯示switch控件,button控件,checkbox控件等。如下圖1.1,WLAN和藍牙上使用到了switch開關。但在L上面,WLAN和藍牙的這兩個開關已經去掉了,如圖1.2,在Settings模塊的首個頁面似乎就只是一個普通的Listview,那它用的還是不是Header呢?或者說取而代之的是什么呢?繼續往下看吧~
圖片-1.1
圖片-1.2
L Settings 模塊首界面初始化流程
L Settings模塊首界面為Settings,繼承自SettingsActivity,SettingsActivity繼承自Activity。
首先看一下Settings.java代碼可以發現它沒有重寫任何SettingsActiviy的方法,也沒有增加任何自己的方法,唯獨增加了許多靜態內部類,如:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * Top-level Settings activity */ public class Settings extends SettingsActivity { /* * 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 */ } public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ } public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ } public static class KeyboardLayoutPickerActivity extends SettingsActivity { /* empty */ } public static class InputMethodAndSubtypeEnablerActivity extends SettingsActivity { /* empty */ } public static class VoiceInputSettingsActivity extends SettingsActivity { /* empty */ } public static class SpellCheckersSettingsActivity extends SettingsActivity { /* empty */ } public static class LocalePickerActivity extends SettingsActivity { /* empty */ } public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ } public static class HomeSettingsActivity extends SettingsActivity { /* empty */ } ... } |
看注釋可以知道,這些子類是為了啟動特定獨立的Settings選項而創建的,例如在某個應用里需要設置無線那么只需要啟動 WirelessSettingsActivity 就可以了。
所以Settings模塊的啟動流程直接看SettingsActiviy就行了。
onCreate方法是Activity的生命周期第一步,看看 SettingsActivity在這里都做了些什么?
| 1 2 3 | // Should happen before any call to getIntent() getMetaData(); |
這個方法用來獲得Activity的額外數據mFragmentClass,如果可以獲得這個數據,那么下面會去顯示mFragmentClass對應的Activity。直接啟動Settings模塊不會獲得這個數據。
| 1 | mIsShowingDashboard = className.equals(Settings.class.getName()); |
這一步很重要,因為我們是從Settings這個Activity過來的,所以這里的 mIsShowingDashboard 為 true 。
| 1 2 3 4 5 6 7 8 9 | // 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,暫時忽略。
| 1 2 3 | setContentView(mIsShowingDashboard ? R.layout.settings_main_dashboard : R.layout.settings_main_prefs); |
前面知道這里的 mIsShowingDashboard為true,所以這里使用的布局文件為R.layout.settings_main_dashboard。settings_main_dashboard.xml文件如下:
| 1 2 3 4 5 6 7 8 9 10 11 | <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,直接走到下面這段
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <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中了。
DashboardSummary走完onCreateView方法后會走onResume,然后一路下來又會調到SettingsActivity的
| 1 | loadCategoriesFromResource(R.xml.dashboard_categories, categories); |
這一步是通過 R.xml.dashboard_categories來加載categories,這里的categorys為ArrayList?mCategories。接著來看看dashboard_categories.xml這個文件吧
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | xml version="1.0" encoding="utf-8" <!-- Copyright (C) 2014 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <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" /> <!--HetComm--> <dashboard-tile android:id="@+id/hetcomm_settings" android:icon="@drawable/ic_settings_hetcomm" android:title="@string/hetcom_setting_title"> <intent android:action="com.android.settings.HETCOMM_SETTINGS" /> </dashboard-tile> <!-- 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" /> <!-- Hotknot --> <dashboard-tile android:id="@+id/hotknot_settings" android:title="@string/hotknot_settings_title" android:fragment="com.mediatek.settings.hotknot.HotKnotSettings" android:icon="@drawable/ic_settings_hotknot" /> <!-- 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.mediatek.audioprofile.AudioProfileSettings" 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" /> <!--Scheduled power on&off--> <dashboard-tile android:id="@+id/power_settings" android:icon="@drawable/ic_settings_schpwronoff" android:title="@string/schedule_power_on_off_settings_title"> <intent android:action="com.android.settings.SCHEDULE_POWER_ON_OFF_SETTING" /> </dashboard-tile> <!-- 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對應dashboard-categorys, DashboardCategory對應dashboard-category,而dashboard-tile則對因代碼中的DashboardTile。
當加載完這些對象后SettingsActivity會將得到的 mCategories 返回給DashboardSummary來初始化Settings的設置選項。
下面這段代碼就是DashboardSummary.rebuildUI()中完成界面的初始化
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 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類。
轉載請注明出處,謝謝~:?http://blog.csdn.net/u011974987/article/details/51004854
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Android 5.1 Settings源码简要分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Settings开发之修
- 下一篇: Android 切换系统语言源码分析