Android P Settings源码 数据加载分析

本文详细分析了Android P Settings的启动流程,包括直接跳转子界面和主界面启动。从SettingsActivity的onCreate方法开始,探讨了如何通过meta-data获取fragment类名并展示指定界面。此外,文章还深入讲解了主界面一级菜单的加载过程,涉及DashboardSummary、CategoryManager和TileUtils等组件,解析AndroidManifest.xml文件以构建设置项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android P Settings


Settings启动流程分析

1.直接跳转子界面

设置是整个android系统的比较重要应用,所涉及到的都是系统功能。

设置为了更方便的区分和获取信息,在AndroidManifest.xml文件中添加了许多的属性,这可能导致很多人看着头疼,但是这也是设置的精髓所在.

第一步:分析AndroidManifest文件,可以看到Settings.java是应用的入口类。

        <!-- Alias for launcher activity only, as this belongs to each profile. -->
        <activity-alias android:name="Settings"
                android:taskAffinity="com.android.settings.root"
                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" />
            </intent-filter>
            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
        </activity-alias>

从代码中可以清楚的看到,Settings 的启动类为 Settings。从 Settings 源码中我们找到了Settings.java文件。。看下面代码:

public class Settings extends SettingsActivity {

    /*
    * Settings subclasses for launching independently.
    */
    public static class AssistGestureSettingsActivity extends SettingsActivity { /* empty */}
    public static class BluetoothSettingsActivity 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 PrivateVolumeForgetActivity extends SettingsActivity { /* empty */ }
    public static class PrivateVolumeSettingsActivity extends SettingsActivity { /* empty */ }
    public static class PublicVolumeSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
    public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }
    public static class AvailableVirtualKeyboardActivity extends SettingsActivity { /* empty */ }
    public static class KeyboardLayoutPickerActivity extends SettingsActivity { /* empty */ }

 Settings中都是些空实现的静态内部类,没有任何与界面加载相关的内容。意义在于这些子类是为了启动特定独立的 Settings 选项而创建的。

我们看SettingsActivity,它继承于SettingsDrawerActivity,而SettingsDrawerActivity内容不多,主要功能是:

1、注册对应用安装、卸载、更新的事件广播,同时更新一级设置列表。

    @Override
    protected void onResume() {
        super.onResume();
        //添加应用安装,卸载,改变,更新监听事件
        final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addDataScheme("package");
        registerReceiver(mPackageReceiver, filter);

        new CategoriesUpdateTask().execute();
    }

2、重写setContentView,让子类调用的setContentView时,将子类布局填充到自己content_frame中。

    @Override
    public void setContentView(@LayoutRes int layoutResID) {
        final ViewGroup parent = findViewById(R.id.content_frame);
        if (parent != null) {
            parent.removeAllViews();
        }
        LayoutInflater.from(this).inflate(layoutResID, parent);
    }

3、当接受到广播时,调用CategoriesUpdateTask,异步更新sTileBlacklist列表,并回调监听事件。

    private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {

        private final CategoryManager mCategoryManager;

        public CategoriesUpdateTask() {
            mCategoryManager = CategoryManager.get(SettingsDrawerActivity.this);
        }

        @Override
        protected Void doInBackground(Void... params) {
            mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this, getSettingPkg());
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            mCategoryManager.updateCategoryFromBlacklist(sTileBlacklist);
            onCategoriesChanged();
        }
    }

我们接着分析Settings中的静态内部类,通过一个例子来了解这个启动流程,如果有别的应用想进入WLAN设置无线网络,只需要启动WLAN对应的类接可以了,不用打开Settings再点击进入WLAN中进行设置,Settings又是继承与SettinggsActivity,初始化界面应该是在父类SettinggsActivity里完成的,下面看一下启动流程:

我们在清单文件中找到WifiSettingsActivity的定义:

        <!-- M: Add mcc | mnc to prevent some cases activity relaunch and cause duplicated WifiDialog ALPS02124573-->
        <activity
            android:name="Settings$WifiSettingsActivity"
            android:label="@string/wifi_settings"
            android:icon="@drawable/ic_settings_wireless"
            android:configChanges="orientation|keyboardHidden|screenSize|mcc|mnc"
            android:taskAffinity="com.android.settings"
            android:parentActivityName="Settings">
            <intent-filter android:priority="1">
                <action android:name="android.settings.WIFI_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" />
                <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.PRIMARY_PROFILE_CONTROLLED"
                android:value="true" />
        </activity>

其中有 meta-data 的标签使用,从这个标签的 key-value 来看,很明显可以认为WifiSettings的具体实现应该是由 WifiSettings 这个 Fragment 来布局渲染的。

            <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
                android:value="com.android.settings.wifi.WifiSettings" />

我们回到 SettingsActivity 中, onCreate() 方法如下: 

    @Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);
        /// M: ALPS02994518 If start by monkey, finish @ {
        if (!isFinishing() && Utils.isMonkeyRunning()) {
            Log.d(LOG_TAG, "finish due to monkey user");
            finish();
            return;
        }
        /// @ }
        Log.d(LOG_TAG, "Starting onCreate");
        long startTime = System.currentTimeMillis();

        final FeatureFactory factory = FeatureFactory.getFactory(this);
        
        //获得DashboardFeatureProviderImpl
        mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this);

        // Should happen before any call to getIntent()
        //将子类在Manifest中com.android.settings.FRAGMENT_CLASS的值赋值给mFragmentClass
        getMetaData();

        //注意:这里getIntent()是自己重写过的方法,并不是Activity自带的getIntent()
        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);

        final ComponentName cn = intent.getComponent();
        final String className = cn.getClassName();//子类名
        
        //如果是Settings界面,即主界面
        mIsShowingDashboard = className.equals(Settings.class.getName());

可以看到,进入 oncreate 里有个 getMetaData(), 这和我们之前看到的清单文件里的meta似乎有某种联系,点进去看,代码如下:

public 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());
        }
    }

可以看到,这个函数的主要作用就是从 Activity 标签中获取 meta-data 标签中key为 com.android.settings.FRAGMENT_CLASS 的值,并将其赋值给 mFragmentClass 这个私有

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值