android框架_5.0的Settings模块的分析1_009

一、我们从最原始的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类的;

 

会继续分析该模块。。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值