轉載請注明出處,謝謝~http://blog.csdn.net/u011974987/article/details/51004854。
概述:
先聲明:本人工作快兩年了,仍是菜鳥級別的。羞愧啊!曾經遇到好多知識點都沒有記錄下來,感覺挺可惜的。如今有機會接觸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的方法。也沒有添加不論什么自己的方法,只有添加了很多靜態內部類,如:
/** * 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即可了。
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中了。
DashboardSummary走完onCreateView方法后會走onResume,然后一路下來又會調到SettingsActivity的
loadCategoriesFromResource(R.xml.dashboard_categories, categories);
這一步是通過 R.xml.dashboard_categories來載入categories,這里的categorys為ArrayList mCategories。
接着來看看dashboard_categories.xml這個文件吧
<?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()中完畢界面的初始化
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);
}
這段代碼我就不詳細分析了,邏輯非常easy,遍歷categories這個列表來獲取DashboardCategory對象。將全部DashboardCategory對象和DashboardCategory對象中的DashboardTile對象轉化為視圖對象並加入到主視圖對象mDashboard中。
到這里SettingsActivity的onCreate方法就算結束了。總結一下,
1.onCreate完畢的任務是切換DashboardSmmary這個Fragment,然后從dashboard_categories.xml中讀取預先配置好的文件來初始化Settings的首界面視圖。
2.L中舍棄了Header類,取而代之的是DashboardCategory和DashboardTile類。