Android 8.0 Settings流程分析与变动

2023-05-16

开! 场!  白! 好! 难! 写!

一,相比Android Settings 7.0

    如下图,在7.0的基础上,去掉了7.0新加的侧滑菜单(可能是觉得有点鸡肋吧)。多加了一级页面,把原来类别标题变成的第一级菜单的子项。在代码架构也稍加变动,并引入架构组件之LifeCycle(生命周期感知,本文不作介绍)。


二,第一级菜单的加载

浏览源码,大多数我们从程序的AndroidManifest.xml入手,这次也不列外。

packages\apps\Settings\AndroidManifest.xml:

<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" />
            </intent-filter>
            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
        </activity-alias>

找到<category android:name="android.intent.category.LAUNCHER" />所属的类,Settings.java。但打开Settings.java类看,除了大量静态类继承SettingsActivity,就没什么东西了。那再去父类SettingsActivity.java找找。

packages\apps\Settings\src\com\android\settings\SettingsActivity.java:

首先当然是onCreate()->

@Override
    protected void onCreate(Bundle savedState) {
        super.onCreate(savedState);
        long startTime = System.currentTimeMillis();
        //工厂类实现方法com.android.settings.overlay.FeatureFactoryImpl.java
        final FeatureFactory factory = FeatureFactory.getFactory(this);
        //获取菜单信息的工厂类,实现类为DashboardFeatureProviderImpl.java
        mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this);
        mMetricsFeatureProvider = factory.getMetricsFeatureProvider();
        // 从intent信息中获取<meta-data/>标签名为"com.android.settings.FRAGMENT_CLASS"的值(下文用于加载Fragment的类名)
        getMetaData();
        ... ...
        //获取上面getMetaData()得到的类名
        final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT);
        //是否为快捷进入方式(如从其它的应用进入Settings的某个设置项)
        mIsShortcut = isShortCutIntent(intent) || isLikeShortCutIntent(intent) ||
                intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, false);
        ... ...
        //当前类是否为Settings.class,即进入方式为点击launcher上的图标进入的主设置界面
        mIsShowingDashboard = className.equals(Settings.class.getName());
        ... ...
        setContentView(mIsShowingDashboard ?
                R.layout.settings_main_dashboard : R.layout.settings_main_prefs);
        mContent = findViewById(R.id.main_content);
        getFragmentManager().addOnBackStackChangedListener(this);
        if (savedState != null) {
          ... ...
        } else {
            //加载布局
            launchSettingFragment(initialFragmentName, isSubSettings, intent);
        }

        ... ...
    }


launchSettingFragment()->

 @VisibleForTesting
    void launchSettingFragment(String initialFragmentName, boolean isSubSettings, Intent intent) {
        if (!mIsShowingDashboard && initialFragmentName != null) {
            ... ...
            switchToFragment(initialFragmentName, initialArguments, true, false,
                mInitialTitleResId, mInitialTitle, false);
        } else {
            // Show search icon as up affordance if we are displaying the main Dashboard
            mDisplayHomeAsUpEnabled = true;
            mInitialTitleResId = R.string.dashboard_title;
            //进入主页走的这里,替换目标Fragment
            switchToFragment(DashboardSummary.class.getName(), null /* args */, false, false,
                mInitialTitleResId, mInitialTitle, false);
        }
    }

继续,我们看看DashboardSummary.java,对于它我们主要是想知道它的数据加载,它是怎么加载自己的子项的。

packages\apps\Settings\src\com\android\settings\dashboard\DashboardSummary.java:

对子项的数据获取在updateCategoryAndSuggestion()中得到实现。

@VisibleForTesting
    void updateCategoryAndSuggestion(List<Tile> suggestions) {
        final Activity activity = getActivity();
        if (activity == null) {
            return;
        }
        /*根据"com.android.settings.category"的值查询子项数据,这里的值为"com.android.settings.category.ia.homepage"。
        具体获取办法追踪到frameworks\base\packages\SettingsLib\src\com\android\settingslib\drawer\TileUtils.java中。
        通过PackageManager查询所有在AndroidManifest.xml中定义<meta-data/>中含有该值的类。注意:会过滤掉非系统级应用的数据!
        有兴趣的自行研究,这里不深究。*/
        final DashboardCategory category = mDashboardFeatureProvider.getTilesForCategory(
                CategoryKey.CATEGORY_HOMEPAGE);
        if (category == null) {
            return;
        }
        mSummaryLoader.updateSummaryToCache(category);
        if (suggestions != null) {
            mAdapter.setCategoriesAndSuggestions(category, suggestions);
        } else {
            //数据的绑定在适配器中,->packages\apps\Settings\src\com\android\settings\dashboard\DashboardAdapter.java
            mAdapter.setCategory(category);
        }
    }

对于第一级菜单的加载。在AndroidManifest.xml中的配置如下列图:


三,第二级菜单的加载

    以上我们知道第一级菜单是完全动态的加载,但二级菜单则是动态加载和静态xml布局文件,就拿“系统”这项为例。

packages\apps\Settings\AndroidManifest.xml:

<activity android:name=".Settings$SystemDashboardActivity"
                  android:label="@string/header_category_system"
                  android:icon="@drawable/ic_settings_about">
            <intent-filter android:priority="-1">
                <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.FRAGMENT_CLASS"
                       android:value="com.android.settings.system.SystemDashboardFragment"/>
            <meta-data android:name="com.android.settings.summary"
                       android:resource="@string/system_dashboard_summary"/>
        </activity>

SystemDashboardFragment.java继承DashboardFragment.java。我们主要观察这个类。

packages\apps\Settings\src\com\android\settings\dashboard\DashboardFragment.java:

1,静态加载部分:

静态加载部分的实现方法为displayResourceTiles()->

	/**
     * Displays resource based tiles.
     */
    private void displayResourceTiles() {
		//获取xml布局文件的id(DashboardFragment.java实现该方法)
        final int resId = getPreferenceScreenResId();
        if (resId <= 0) {
            return;
        }
        addPreferencesFromResource(resId);
        final PreferenceScreen screen = getPreferenceScreen();
		/** 实现布局文件中的子项控件的业务逻辑
		 *  DashboardFragment.java的子类实现getPreferenceControllers()方法,该方法加载继承于AbstractPreferenceController.java的实现业务逻辑类
		 */
        Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
        for (AbstractPreferenceController controller : controllers) {
            controller.displayPreference(screen);
        }
    }

2,动态加载部分:

动态加载部分的实现方法refreshDashboardTiles()->

/**
     * Refresh preference items backed by DashboardCategory.
     */
    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
    void refreshDashboardTiles(final String TAG) {
        final PreferenceScreen screen = getPreferenceScreen();
		/* 获取子项 
		 * getCategoryKey()从DashboardFragmentRegistry.PARENT_TO_CATEGORY_KEY_MAP中获取Category值。
		 * 该值通过类名获取
		 * 存:PARENT_TO_CATEGORY_KEY_MAP.put(SystemDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM);
		 * CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
		 */
        final DashboardCategory category =
                mDashboardFeatureProvider.getTilesForCategory(getCategoryKey());
        ... ...
        // Install dashboard tiles.
        for (Tile tile : tiles) {
            ... ...
            if (mDashboardTilePrefKeys.contains(key)) {
                ... ...
            } else {
                // Don't have this key, add it.
                final Preference pref = new Preference(getPrefContext());
				/*在这里进行绑定,加载
				 *packages\apps\Settings\src\com\android\settings\dashboard\DashboardFeatureProviderImpl.java->bindPreferenceToTile()
				 */
                mDashboardFeatureProvider.bindPreferenceToTile(getActivity(), getMetricsCategory(),
                        pref, tile, key, mPlaceholderPreferenceController.getOrder());
                mProgressiveDisclosureMixin.addPreference(screen, pref);
                mDashboardTilePrefKeys.add(key);
            }
            remove.remove(key);
        }
        // Finally remove tiles that are gone.
        for (String key : remove) {
            mDashboardTilePrefKeys.remove(key);
            mProgressiveDisclosureMixin.removePreference(screen, key);
        }
        mSummaryLoader.setListening(true);
    }

该文的Settings加载流程就差不多到这里了。

四,顺便说说

下拉菜单栏时长按设置图标进入设置,在系统项里面会多一个《系统界面调节工具》。那么这是怎么显示和隐藏的了?

frameworks\base\packages\SystemUI\src\com\android\systemui\tuner\TunerService.java

->setTunerEnabled():

public static final void setTunerEnabled(Context context, boolean enabled) {
		//隐藏应用图标,隐藏某个组件启动也可以使用该方法
        userContext(context).getPackageManager().setComponentEnabledSetting(
                new ComponentName(context, TunerActivity.class),
                enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 8.0 Settings流程分析与变动 的相关文章

随机推荐

  • java -虹软Caused by: java.lang.UnsatisfiedLinkError: Can‘t load library: **\WIN64\libarcsoft_face.dll

    错误详情 Caused by java lang UnsatisfiedLinkError Can t load library F code WIN64 libarcsoft face dll 如图 xff1a 错误原因 一般遇到问题 x
  • Fragment的使用(Android实现底部导航栏)

    xfeff xfeff xfeff xfeff 一 布局页面添加 1 添加四个切换页面的布局 xff08 1 xff09 四个切换页面的布局 四个页面相同 xff09 xff1a lt xml version 61 34 1 0 34 en
  • Java 线程安全

    引入1 xff1a 计算机内存模型 span class token number 1 span 因为向主内存中读写数据的速度要远远小于 span class token constant CPU span 处理数据的速度 xff0c 所有
  • Debian11安装MySql8

    下载地址点击这里 官方安装文档点击这里 Installing MySQL on Linux Using Debian Packages from Oracle xff09 安装 span class token comment 安装依赖 s
  • 消息队列技术的介绍和原理(MQ)

    最近要做一个项目准备用分布式消息队列 xff0c 花点时间看了下 消息队列技术是分布式应用间交换信息的一种技术 消息队列可驻留在内存或磁盘上 队列存储消息直到它们被应用程序读走 通过消息队列 xff0c 应用程序可独立地执行 它们不需要知道
  • win10如何修改C盘User下的用户名

    温馨提示 仅供参考 xff0c 不建议小白在本机测试 xff0c 不然会有需要 重装 的风险 建议操作前设置还原点 重要数据备份 xff01 xff01 xff01 然后Win11就别尝试了 xff0c 而且一旦失败的话 xff0c 就只能
  • 极狐Gitlab操作手册

    用户管理 普通用户可以访问他们的群组和项目 用户可以无限制地访问所有群组 项目 用户和功能 群组管理 项目管理 创建项目 为项目添加成员 其它设置 为当前用户配置SSH密钥 本地生成SSH密钥 提交本地项目到gitlab span clas
  • WIN11之RocketMQ5.0安装

    官网地址 xff1a https rocketmq apache org docs quick start 下载地址 xff1a https rocketmq apache org dowloading 下载 系统要求 span class
  • Kubernetes 对象

    什么是对象 K8s集群中创建的任何东西都可以被视为对象 xff1a Deployment Pod Service等等 对象类型 kubectl api resources span class token comment 查询所有type
  • K8S DashBoard控制台

    前言 Dashboard 是基于网页的 Kubernetes 用户界面 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中 xff0c 也可以对容器应用排错 xff0c 还能管理集群资源 你可以使用 Dashbo
  • Debian11之基于二进制安装K8S(v1.26.x) 集群

    官网地址 xff1a https kubernetes io zh cn docs home supported doc versions 资源列表 主机IP主机名称主机角色软件192 168 111 30master1主节点1kube a
  • Kubernetes Service、Ingress、Ingress Controller

    Kubernetes 网络模型 K8S 是一种容器编排系统 xff0c 可以方便地管理和部署容器应用程序 它支持通过四层负载和七层负载向容器集群中的应用程序提供负载均衡 四层负载是一种基于传输层协议 xff08 例如TCP UDP xff0
  • 浅析JAVA中的抽象类

    span class hljs keyword abstract span class Animal span class hljs keyword abstract span span class hljs keyword void sp
  • 安装 Ubuntu

    1 del 进入bios 选择从USB启动 2 安装ubuntu 3 准备安装Ubuntu 不用选 4 安装类型 选择something else 可以自己分区 5 分为四个区 swap 交换分区 不用格式化 boot 引导和内核分区 格式
  • Linux安装libpcap(pcap.h库)(以Ubuntu 18.04为例)

    做毕业设计需要用到libpcap来抓包 借此次机会完整记录下自己的安装过程 xff0c 前人种树后人乘凉 到libpcap官网去下载最新的源码包 下载完成后tar xzf 文件 tar gz 解压 xff0c 于是我们可以看到完整的源码目录
  • rabbitmq的waitForConfirms和waitForConfirmsOrDie作用和区别

    rabbitmq的waitForConfirms和waitForConfirmsOrDie作用和区别 解决方法 xff1a 发布消息后通过执行channel waitForConfirmsOrDie xff08 long xff09 方法或
  • 环形缓冲区的实现原理(ring buffer)

    消息队列锁调用太频繁的问题算是解决了 xff0c 另一个让人有些苦恼的大概是这太多的内存分配和释放操作了 频繁的内存分配不但增加了系统开销 xff0c 更使得内存碎片不断增多 xff0c 非常不利于我们的服务器长期稳定运行 也许我们可以使用
  • 解决mac安装anaconda后遇到“conda: command not found“的问题

    最近新入了macbook pro xff0c 在安装好anaconda后 xff0c 图形界面中操作时没有任何问题的 xff0c 但打开终端后却遇到了conda指令无法使用的问题 xff0c 如下图 xff1a 这个问题的产生可能会有多种原
  • Android 7.0 Launcher3 去掉应用抽屉

    年初做过一个项目 xff0c 有一个需求就是需要将桌面变为单层不需要二级菜单 最近几次有小伙伴有这个问我这个解决办法 现在我将分享给大家 先上效果图 xff1a 功能分解 去除Allapp键 xff0c 调整HotSeat布局将所有应用摆在
  • Android 8.0 Settings流程分析与变动

    开 xff01 场 白 xff01 好 xff01 难 xff01 写 xff01 一 xff0c 相比Android Settings 7 0 如下图 xff0c 在7 0的基础上 xff0c 去掉了7 0新加的侧滑菜单 xff08 可能