android O版本 设置(Settings)模块总结--设置的启动界面选择

本文深入解析Android系统的设置模块,从SettingsActivity的启动流程到不同界面的加载机制,包括主界面、内部类界面及SubSettings界面的布局差异。揭示了设置模块如何通过类名判断加载不同布局,以及Fragment在界面跳转中的作用。
摘要由CSDN通过智能技术生成

之前一直在公司做设置模块的功能修改,现在转到了其它模块,所以就总结一下吧,有不足之处,还请指正.

设置是整个android系统的重要应用,涉及的都是系统功能,本文只是对其结构进行解析,功能控制等不做说明

(1)设置的界面选择

设置里面的Activity乍一看和常规应用的Activity有很大不同,但是原理都是一样的,不过设置为了更方便的区分和获取信息,在AndroidManifest.xml文件中添加了许多的属性,这可能导致很多人看着头疼,但是这也是设置的精髓所在.

 

设置的启动界面: O/packages/apps/Settings/src/com/android/settings/Settings.java

Settings的父类是SettingsActivity,而且其中有很多继承SettingsActivity的内部类,这个地方是很有意思,后续再说,先看下SettingsActivity.java

O/packages/apps/Settings/src/com/android/settings/SettingsActivity.java

SettingsActivity的父类是SettingsDrawerActivity,而SettingsDrawerActivity是在SettingLib中定义

O/frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java

SettingsDrawerActivity名称是沿用N版本的名字,但是侧滑栏功能在O版本上已经移除了,google在这个地方偷了下懒.

这父子俩的onCreate():

  SettingsDrawerActivity
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //主要是布局设置
        super.setContentView(R.layout.settings_with_drawer);
        mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);

        Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
        if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
            toolbar.setVisibility(View.GONE);
            return;
        }
        setActionBar(toolbar);
    }


SettingsActivity
    @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);
       ...... 
        //获取的类名,此处获取的可能是在Settings.java中的内部类,或者就是Settings.java

        // Should happen before any call to getIntent()
        getMetaData();
        // Getting Intent properties can only be done after the super.onCreate(...)
        final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
        ......
        final ComponentName cn = intent.getComponent();
        final String className = cn.getClassName();
        //mIsShowingDashboard会根据不同的类名布置不同的布局
        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 Intent
        final boolean isSubSettings = this instanceof SubSettings ||
                intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false);

        // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content
        // insets
        //设置二级界面的主题
        if (isSubSettings) {
            setTheme(R.style.Theme_SubSettings);
        }
        //布局不同的布置,主要是为了区分一级界面
        setContentView(mIsShowingDashboard ? R.layout.settings_main_dashboard : R.layout.settings_main_prefs);

        mContent = (ViewGroup) findViewById(R.id.main_content);

        getFragmentManager().addOnBackStackChangedListener(this);
       ......
        //跳转到制定的界面
        launchSettingFragment(initialFragmentName, isSubSettings, intent);

       ......
    }

在SettingsActivity的onCreate中去其实会有三个不同布局的加载方向,以下是重点了:

Settings , Settings的内部类 , SubSettings

(a)Settings ---主界面(一级界面)

onCreate函数中会根据类名加载不同的布局,而布尔值:mIsShowingDashboard 就是当前是否为一级界面的判断

        mIsShowingDashboard = className.equals(Settings.class.getName());
        setContentView(mIsShowingDashboard ?
                R.layout.settings_main_dashboard : R.layout.settings_main_prefs);

 

settings_main_dashboard.xml就很简单了只是一个FrameLayout

 

<?xml version="1.0" encoding="utf-8"?>
<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"
             />

在之后的界面跳转即 launchSettingFragment(initialFragmentName, isSubSettings, intent)函数中又做出了区分:

    void launchSettingFragment(String initialFragmentName, boolean isSubSettings, Intent intent) {
        if (!mIsShowingDashboard && initialFragmentName != null) {
            ......
        } 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 /* args */, false, false,
                mInitialTitleResId, mInitialTitle, false);
        }
    }

在launchSettingFragment函数中正式加载了设置的一级界面DashboardSummary.java,DashboardSummary是一个Fragment,而内部布局是使用的R.layout.dashboard,dashboard.xml包含了一个自定义的RecyclerView类FocusRecyclerView,此处就不再详细说明了.

(b)Settings的内部类

Settings的内部类的启动一版都是通过activity 中的action属性启动的,而判断的依据也是通过mIsShowingDashboard,加载的布局为R.layout.settings_main_prefs,而settings_main_prefs.xml比dashboard.xml来说就增加了一个switchBar:

<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"
                />

    </LinearLayout>

    <RelativeLayout /><!--没怎么研究过,此处代码就省略了-->

</LinearLayout>

Settings的内部类的主体显示内容依然是一个Fragment,而这个Fragment已经在AndroidManifest.xml中定义好了.拿StorageDashboardActivity为例:

        <activity android:name=".Settings$StorageDashboardActivity"
                android:label="@string/storage_settings"
                android:icon="@drawable/ic_settings_storage"
                android:taskAffinity="com.android.settings"
                android:parentActivityName="Settings">
            <intent-filter android:priority="1">
                <action android:name="android.settings.INTERNAL_STORAGE_SETTINGS" />
                <action android:name="android.settings.MEMORY_CARD_SETTINGS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.VOICE_LAUNCH" />
            </intent-filter>
            <intent-filter android:priority="5">
                <action android:name="com.android.settings.action.SETTINGS" />
            </intent-filter>
            <meta-data android:name="com.android.settings.category"
                android:value="com.android.settings.category.ia.homepage" />
            <meta-data android:name="com.android.settings.title"
                android:resource="@string/storage_usb_settings" />
            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                android:value="com.android.settings.deviceinfo.StorageSettings" />
            <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
                android:value="true" />
        </activity>

这个地方很容易会让人迷糊的,主要是里面的属性太多,看第一眼估计就会晕掉,这些属性是在SettingLib中的O/frameworks/base/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java有用到的,后续有时间的话可以总结一下,TileUtils主要目录加载的工具类.

言归正传,内部类StorageDashboardActivity的Fragment显示内容为:com.android.settings.FRAGMENT_CLASS,即com.android.settings.deviceinfo.StorageSettings
(c)SubSettings

和内部类就很相似了,不过是做了主题的切换:

        if (isSubSettings) {
            setTheme(R.style.Theme_SubSettings);
        }

SubSettings的启动方式是很隐蔽的这里把启动的顺序贴下,各位有时间的话可以自己研究一下:

android.support.v7.preference.Preference$1.onClick()
android.support.v7.preference.Preference.performClick()
com.android.settings.fuelgauge.PowerUsageSummary.onPreferenceTreeClick()
com.android.settings.dashboard.DashboardFragment.onPreferenceTreeClick()
android.support.v14.preference.PreferenceFragment.onPreferenceTreeClick()
com.android.settings.SettingsActivity.onPreferenceStartFragment()
com.android.settings.SettingsActivity.startPreferencePanel()
com.android.settings.Utils.startWithFragment()
com.android.settings.Utils.onBuildStartFragmentIntent()

 

到这里为止,设置的界面加载启动基本上已经总结完了,看起来还是很简单的,但是这只是启动而已,内部的数据加载,数据与View的绑定其实还有很多东西,后续有时间的话会继续总结.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值