Android 5.1 Settings模块源码分析
来源:互联网 发布:unity3d 模拟重力跳跃 编辑:程序博客网 时间:2024/05/16 06:13
前述:
本人已工作两年多,但是依然感觉还是Android的门外汉,之前一直从事Android的应用开发,每天就是各种调用SDK方法,各种拷贝网上的源码以及jar包,从来也不管为啥这样用,由于换了一份工作才开始接触到Android的源码,感觉Android的水好深啊。
今天这篇博客也是我的处女作啊,以后也希望通过多多研究源码来写出更多的博客,我觉得写博客主要还是作为一个记录吧,不然感觉有的东西真的很容易丢,尤其是平时不怎么接触的模块。
好啦,接下来开始今天的Setting旅行啦。
Settings简述:
Setting模块大家还是比较熟悉的吧?其实Setting也不是什么高级的东西,它就是一个APP,属于Android的应用层,源码在packages\apps\Settings中,今天分析的源码是基于Android5.1,如下图是5.1Setting模块的界面:
查看一个应用首先是查看这个应用的AndroidManifest.xml文件,以便查看程序的入口,Setting模块的入口是Setting.java这个类,这个类继承SettingActivity,但是没有继承任何的方法,但却定义了一大堆内部类。
/** * Top-level Settings activity */public class Settings extends SettingsActivity { 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 */ } public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ } public static class DeviceInfoSettingsActivity extends SettingsActivity { /* empty */ } public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ } public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ }}
这些类都是Setting模块的子界面类,是特定功能的类,比如WifiSettingsActivity是WiFi模块相关的类。
所以接下来我们直接分析SettingActivity这个类就可以了。
SettingActivity.java:
先看该类的OnCreate方法
@Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); // Should happen before any call to getIntent() getMetaData(); final Intent intent = getIntent();
先调用getMetaData()方法,用于加载一些元数据,进入getMetaData()方法
private void getMetaData() { try { ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); if (ai == null || ai.metaData == null) return; mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS); } catch (NameNotFoundException nnfe) { // No recovery Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString()); }}
主要作用就是通过META_DATA_KEY_FRAGMENT_CLASS这个属性获得额外的mFragmentClass,如果可以获得将启动对应的mFragmentClass的Activity,但是直接启动Setting不会获得该数据。
继续往下看代码
final ComponentName cn = intent.getComponent();final String className = cn.getClassName();mIsShowingDashboard = className.equals(Settings.class.getName());// This is a "Sub Settings" when:// - this is a real SubSettings// - or :settings:show_fragment_as_subsetting is passed to the Intentfinal boolean isSubSettings = className.equals(SubSettings.class.getName()) || intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);
由于我们是从Setting启动的,所以mIsShowingDashboard的值为true,而isSubSettings的值是false。
setContentView(mIsShowingDashboard ?R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
由于mIsShowingDashboard的值为true,所以使用的是R.layout.settings_main_dashboard
<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" />
同时继续往下走,会看到这段代码块:
if (savedState != null) { ... } else { if (!mIsShowingDashboard) { ... } else {// No UP affordance if we are displaying the main DashboardmDisplayHomeAsUpEnabled = false; // Show Search affordance mDisplaySearch = true; mInitialTitleResId = R.string.dashboard_title; switchToFragment(DashboardSummary.class.getName(), null, false, false, mInitialTitleResId, mInitialTitle, false); }}
这里由于是第一次启动,所以savedState 为null,同时mIsShowingDashboard的值为true,看到进入了switchToFragment这个方法,这里准备切换到DashboardSummary这个Fragment。
DashboardSummary.java
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>
private void rebuildUI(Context context) { if (!isAdded()) { Log.w(LOG_TAG, "Cannot build the DashboardSummary UI yet as the Fragment is not added"); return; } long start = System.currentTimeMillis(); final Resources res = getResources();//mDashboard这个View就是整个界面的总View mDashboard.removeAllViews();(1)这里调用SettingActivity的getDashboardCategories,也就是加载整个Setting的内容 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);//(2)创建DashboardTileView,也就是每个Setting的内容 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); } long delta = System.currentTimeMillis() - start; Log.d(LOG_TAG, "rebuildUI took: " + delta + " ms");}
接下来将对上面代码标注的序号处进行说明:
(1)处最终会调用SettingActivity的buildDashboardCategories方法,
private void buildDashboardCategories(List<DashboardCategory> categories) { categories.clear(); loadCategoriesFromResource(R.xml.dashboard_categories, categories); updateTilesList(categories);}
该方法将加载一个xml文档并使用Android默认的xml解析器XmlPullParser对文档进行解析,最终将解析结果存入到一个List<DashboardCategory>中,然后在上面代码的rebuildUI方法中for循环遍历读取。
以下为Setting页面的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" /> <!-- 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" > <!-- Hard key --> <dashboard-tile android:id="@+id/hard_key_settings" android:title="@string/hard_key_settings" android:icon="@drawable/ic_settings_hardkey"> <intent android:action="android.intent.action.MAIN" android:targetClass="com.android.settings.HardKeySettings" android:targetPackage="com.android.settings" /> </dashboard-tile> <!-- 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" /> <!-- SPRD:add AudioProfile in setting @{ --> <dashboard-tile android:id="@+id/notification_settings" android:icon="@drawable/ic_settings_notifications" android:title="@string/audio_profiles" > <intent android:action="android.intent.action.MAIN" android:targetClass="com.sprd.audioprofile.AudioProfileSettings" android:targetPackage="com.sprd.audioprofile" /> </dashboard-tile> <!-- @} --> <!-- SPRD:add notification in setting @{ --> <!-- Notifications --> <dashboard-tile android:id="@+id/notification_settings" android:title="@string/prompt_notification_settings" android:fragment="com.android.settings.notification.NotificationSettings" android:icon="@drawable/ic_settings_situation" /> <!-- 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" /> <!-- Uninstall application --> <dashboard-tile android:id="@+id/uninstall_settings" android:title="@string/delete_applications" android:fragment="com.android.settings.applications.SprdUninstallApplications" android:icon="@drawable/ic_settings_uninstall" /> <!-- 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" /> <!-- SPRD: add by Bug 372436, Regular boot development @{ --> <dashboard-tile android:id="@+id/power_alarm" android:icon="@drawable/ic_settings_power_off" android:title="@string/swtichmachine" > <intent android:action="android.intent.action.MAIN" android:targetClass="com.sprd.settings.timerpower.AlarmClock" android:targetPackage="com.android.settings" /> </dashboard-tile> <!-- @} --> </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-categories这个标签对应着Java代码中的List<DashboardCategory>集合,dashboard-category这个标签对应着DashboardCategory类,dashboard-tile这个标签对应着DashboardTile这个类。
(2)处将通过for循环遍历而来的数据通过创建DashboardTileView最终全部存入到mDashboard这个布局中,至此整个Setting模块的界面布局已经完成了。
DashboardTileView.java
这个类是Setting中每个条目数据的类,通过onClick方法启动不同的功能,比如WiFi,Bluetooth等
public class DashboardTileView extends FrameLayout implements View.OnClickListener { @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); } }}
最终启动不同的Setting子模块,至此整个Setting模块的整体框架就已分析结束了。
总结一下:
1、整个Setting模块是在SettingActivity中加载DashboardSummary这个Fragment,然后从dashboard_categories.xml中读取预先配置好的文件来初始化Settings的首界面视图。
2、Setting的子界面基本上都是一个Fragment,并且基本上都是通过SettingActivity的OnCreate方法去加载的,同时大部分SubSetting在加载界面时,用的都是PreferenceFragment技术(在以后的博客中会讲述)。
3、Android5.1的Setting使用的是DashboardCategory和DashboardTile类来存储整个xml数据结构。
- Android 5.1 Settings模块源码分析
- Android Settings模块分析
- Android Settings模块分析
- Android Settings模块分析
- Android 5.1 Settings源码简要分析
- Android 5.1 Settings源码简要分析
- Android 5.1settings源码简要分析
- Android 5.1 Settings源码简要分析
- 20150623----Android-Settings源码分析
- Android Settings源码流程分析
- Android原生Settings源码分析
- Android Settings(系统设置)源码分析(一)
- Android Settings(系统设置)源码分析(一)
- WINDOWS下ECLIPSE ANDROID源码SETTINGS模块调试
- Windows下Eclipse Android源码Settings模块调试
- Settings源码分析
- Scrapy-settings源码分析
- Settings源码分析
- Delphi编写数据库程序要点
- iOS开发从入门到精通-- 警告对话框UIAlertView和等待提示器UIActivityIndicatorView
- android studio 打包签名
- 海选女主角 hd 2022
- TCP详解
- Android 5.1 Settings模块源码分析
- 百度地图androidSDK历史版本大全
- DM8168学习--引导顺序
- windows api第2章总结
- Android开发笔记(一百一十三)测试工具
- [leetcode] 181. Employees Earning More Than Their Managers
- 在Intellij Idea中怎么引入c标签
- 单链表结构和顺序存储结构
- 数组及数组和指针的区别