一、我们从最原始的AndroidManifest.xml文件开始分析:
<manifest xmlns:android="http://schemas.android.com/ak/res/android"
package="com.android.settings"
coreApp="true"
android:sharedUserId="android.uid.system">
<original-package android:name="com.android.settings" />
1、这是文件的大概信息,有包名,uid,还有这是coreApp应用;
<!-- Settings -->
<activity android:name="Settings"
android:taskAffinity="com.android.settings"
android:label="@string/settings_label_launcher"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.settings.SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.APP_SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
android:value="true" />
</activity>
<!-- Alias for launcher activity only, as this belongs to each profile. -->
<activity-alias android:name="Settings"
android:taskAffinity="com.android.settings"
android:label="@string/settings_label_launcher"
android:launchMode="singleTask"
android:targetActivity="Settings">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.APP_SETTINGS" />
</intent-filter>
</activity-alias>
2、从以上信息可以看到Settings.java是Launcher的主Activity;因为有一个 这样的属性:
<category android:name="android.intent.category.LAUNCHER" />,来看一下这个Activity中有些什么?
/**
* 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 */ }
......
/**M: Add new for settings activity @{*/
public static class HDMISettingsActivity extends SettingsActivity { /* empty */ }
public static class BeamShareHistoryActivity extends SettingsActivity { /* empty */ }
......
/**@}*/
}
3、Settings.java文件中里定义了大量的静态内部类,却没有任何跟界面显示相关的内容,都是继承SettingsActivity;而且都是空类;也就是说这个可以肯定设置就只有一个Activity;Settings;
<!-- Top-level settings -->
<activity android:name="Settings$WifiSettingsActivity"
android:taskAffinity=""
android:label="@string/wifi_settings"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.settings.WIFI_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.VOICE_LAUNCH" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.wifi.WifiSettings" />
<meta-data android:name="com.android.settings.TOP_LEVEL_HEADER_ID"
android:resource="@id/wifi_settings" />
</activity>
4、WifiSettingsActivity是一个空的activity;这上面的代码可以看出,通过属性action:android.settings.WIFI_SETTINGS 可以打开这个WifiSettingsActivity界面:如下代码所示:
Intent intent = new Intent("android.settings.WIFI_SETTINGS");
Context.startActivity(intent);
public class SettingsActivity extends Activity
implements PreferenceManager.OnPreferenceTreeClickListener,
PreferenceFragment.OnPreferenceStartFragmentCallback,
ButtonBarHandler, FragmentManager.OnBackStackChangedListener,
SearchView.OnQueryTextListener, SearchView.OnCloseListener,
MenuItem.OnActionExpandListener {
private static final String LOG_TAG = "Settings";
///M: change backup reset title
private ISettingsMiscExt mExt;
5、SettingsActivity这个类中是父类,这里定义了很多东西;实现了很多的接口;下面来分析一下它是怎么加载的,Activity类,顾名思义,首先看的是onCreate()方法:
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
mExt = UtilsExt.getMiscPlugin(this);
mIsWifiOnly = Utils.isWifiOnly(this);
// Should happen before any call to getIntent()
getMetaData();
6、从onCreate方法中可以看出,有一个函数getMetaData(),是获取配置信息的:
private static final String META_DATA_KEY_FRAGMENT_CLASS =
"com.android.settings.FRAGMENT_CLASS";
......
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());
}
}
7、从上面的代码中可以看出GET_META_DATA类型的数据是如下配置信息:
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.wifi.WifiSettings" />
8、获取的是WifiSettings.java类,也就是说getMetaData函数中mFragmentClass获取的就是这个类;
com.android.settings.wifi.WifiSettings;既然mFragmentClass已经指定为具体Fragment的路径,那我们回到onCreate函数,看一下activity是如何加载fragment的。
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
mExt = UtilsExt.getMiscPlugin(this);
mIsWifiOnly = Utils.isWifiOnly(this);
// Should happen before any call to getIntent()
getMetaData();
final Intent intent = getIntent();
if (intent.hasExtra(EXTRA_UI_OPTIONS)) {
getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
}
........
// Getting Intent properties can only be done after the super.onCreate(...)
final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);
final ComponentName cn = intent.getComponent();
final String className = cn.getClassName();
mIsShowingDashboard = className.equals(Settings.class.getName());
.........
setContentView(mIsShowingDashboard ?
R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
mContent = (ViewGroup) findViewById(R.id.main_content);
9、上面注释说getMetaData()要在getIntent()函数之前执行,看一下getIntent的实现,来了解为什么会有这样的规定。getIntent源码如下:
@Override
public Intent getIntent() {
Intent superIntent = super.getIntent();
String startingFragment = getStartingFragmentClass(superIntent);
// This is called from super.onCreate, isMultiPane() is not yet reliable
// Do not use onIsHidingHeaders either, which relies itself on this method
if (startingFragment != null) {
Intent modIntent = new Intent(superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
Bundle args = superIntent.getExtras();
if (args != null) {
args = new Bundle(args);
} else {
args = new Bundle();
}
args.putParcelable("intent", superIntent);
modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
return modIntent;
}
return superIntent;
}
/**
* Checks if the component name in the intent is different from the Settings class and
* returns the class name to load as a fragment.
*/
private String getStartingFragmentClass(Intent intent) {
if (mFragmentClass != null) return mFragmentClass;
String intentClass = intent.getComponent().getClassName();
if (intentClass.equals(getClass().getName())) return null;
if ("com.android.settings.ManageApplications".equals(intentClass)
|| "com.android.settings.RunningServices".equals(intentClass)
|| "com.android.settings.applications.StorageUse".equals(intentClass)) {
// Old names of manage apps.
intentClass = com.android.settings.applications.ManageApplications.class.getName();
}
return intentClass;
}
10、可以看出,getIntent的作用就是构造了一个Intent,并且给它增加了一个特殊的键值对,key为”:settings:show_fragment”,value为mFragmentClass指定的Fragment类名。 之所以要先执行getMetaData,是因为mFragmentClass赋值是在getMeatData中进行的。分析了getIntent,我们继续来看onCreate函数,看看这个intent到底是如何被使用的。
protected void onCreate(Bundle savedState) {
.........
final ComponentName cn = intent.getComponent();
final String className = cn.getClassName(); // 本例中,className为WifiSettingsActivity
mIsShowingDashboard = className.equals(Settings.class.getName()); // 该值为false
// 由于mIsShowingDashboard为false,所以WifiSettingsActivity加载的布局为R.layout.settings_main_prefs
setContentView(mIsShowingDashboard ?
R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
mContent = (ViewGroup) findViewById(R.id.main_content); // 获取承载Fragment的ViewGroup
}
11、这里会去加载一个布局文件,并且这里有两个布局文件,那么我们来分析主要内容的布局问题:settings_main_prefs.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_height="0px"
android:layout_width="match_parent"
android:layout_weight="1">
<com.android.settings.widget.SwitchBar android:id="@+id/switch_bar"
android:layout_height="?android:attr/actionBarSize"
android:layout_width="match_parent"
android:background="@drawable/switchbar_background"
android:theme="?attr/switchBarTheme"
/>
<FrameLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/preferenceBackgroundColor"
/>
</LinearLayout>
......
</LinearLayout>
12、这里的布局文件代码比较,main_content加载fragment类的内容;上下布局;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
mExt = UtilsExt.getMiscPlugin(this);
mIsWifiOnly = Utils.isWifiOnly(this);
// Should happen before any call to getIntent()
getMetaData();
......
setTitleFromIntent(intent);
Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
switchToFragment(initialFragmentName, initialArguments, true, false,
mInitialTitleResId, mInitialTitle, false);
......
}
13、从setTitleFromIntent(intent),是设置标题的;然后获取一个初始化的参数,这个参数是switchToFragment()有两个参数:
initialFragmentName是初始化获取到的需要显示的Fragment类,第二个参数是传递给Fragment类的;
会继续分析该模块。。。。。。。