深入 AOSP:深色模式原理与 Framework 源码解析

QuibblerQuibbler 2020-07-25 约 13 分钟 161 次阅读

深入 AOSP:深色模式原理与 Framework 源码解析

深色模式(Dark Mode)是 Android 10(API 29)引入的一项系统级功能,允许用户在深色背景下使用设备,减少眼睛疲劳,延长电池续航。从 Framework 层面来看,深色模式涉及多个系统服务的协同工作。

1、深色模式概述

深色模式的核心组件包括:
       • UiModeManager:管理 UI 模式切换
       • ThemeManagerService:主题管理服务
       • ResourcesManager:资源管理
       • WindowManagerService:窗口管理

2、UiModeManager 核心实现

UiModeManager 是深色模式的入口类,负责管理系统 UI 模式。源码位置:frameworks/base/core/java/android/app/UiModeManager.java

2.1、模式类型

• MODE_NIGHT_NO:强制浅色模式
       • MODE_NIGHT_YES:强制深色模式
       • MODE_NIGHT_AUTO:自动切换(根据时间或光线)
       • MODE_NIGHT_FOLLOW_SYSTEM:跟随系统设置

2.2、核心实现逻辑

public void setApplicationNightMode(int mode) {
    if (mService != null) {
        try {
            mService.setNightModeForPackage(mPackageName, mode);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}

3、ThemeManagerService 工作机制

ThemeManagerService 是系统级主题管理服务。源码位置:frameworks/base/services/core/java/com/android/server/wm/ThemeManagerService.java

3.1、服务启动流程

1. 在 SystemServer 中启动
       2. 监听系统设置变化
       3. 管理主题配置
       4. 通知应用更新

3.2、配置更新流程

1. 更新 PackageManager 的主题配置
       2. 触发 Configuration 变化
       3. 通知所有 Activity 重建
       4. 更新 WindowManager 的窗口主题

4、Resources 层级适配机制

资源系统通过限定符目录处理深色模式资源。源码位置:frameworks/base/core/java/android/content/res/ResourcesManager.java

4.1、资源加载优先级

1. night-vXX 目录(深色模式专用)
       2. values-vXX 目录(通用)
       3. values 目录(默认)

4.2、资源匹配流程

public ResourcesImpl createResourcesImpl(ResourcesKey key) {
    // 检查夜间模式标志
    if ((key.mFlags & ResourcesKey.FLAG_NIGHT_MODE) != 0) {
        // 优先加载夜间模式资源
        loadNightModeResources(key);
    }
    // 创建 ResourcesImpl
    return new ResourcesImpl(key, mClassLoader);
}

5、WindowManagerService 窗口主题更新

WMS 负责将主题应用到所有窗口。源码位置:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

void applyThemeToWindow(WindowState win) {
    // 获取窗口的主题配置
    int nightMode = win.mAttrs.getNightMode();

    // 如果是系统窗口,使用系统主题
    if (win.isSystemWindow()) {
        nightMode = mThemeManager.getSystemNightMode();
    }

    // 应用主题到窗口
    win.applyNightMode(nightMode);

    // 触发窗口重绘
    win.scheduleLayout();
}

6、应用层适配机制

6.1、Activity 生命周期回调

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // 检查深色模式状态
    int uiMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
    if (uiMode == Configuration.UI_MODE_NIGHT_YES) {
        // 切换到深色模式
        applyDarkTheme();
    } else {
        // 切换到浅色模式
        applyLightTheme();
    }
}

6.2、资源限定符示例

• res/values/colors.xml(默认)
       • res/values-night/colors.xml(深色模式)
       • res/drawable/ic_icon.png(默认)
       • res/drawable-night/ic_icon.png(深色模式)

7、系统级深色模式切换流程

完整的切换流程:
       用户触发 -> Settings -> UiModeManager -> ThemeManagerService -> PackageManager -> ResourcesManager -> WindowManagerService -> 所有应用 Activity 重建 -> 资源重新加载 -> UI 更新

7.1、关键时序

1. 用户在设置中切换深色模式
       2. Settings 调用 UiModeManager.setNightMode()
       3. UiModeManager 通过 Binder 调用 ThemeManagerService
       4. ThemeManagerService 更新系统配置
       5. 广播 Configuration 变化
       6. 所有应用收到通知并重建
       7. 资源系统加载对应主题资源

8、源码中的关键数据结构

public final class NightModeConfiguration {
    public final int mode;           // 夜间模式类型
    public final long startTime;     // 自动模式开始时间
    public final long endTime;       // 自动模式结束时间
    public final boolean override;   // 是否覆盖应用设置

    public NightModeConfiguration(int mode, long startTime, long endTime, boolean override) {
        this.mode = mode;
        this.startTime = startTime;
        this.endTime = endTime;
        this.override = override;
    }
}

9、常见问题与优化

9.1、应用切换深色模式时闪屏

解决方案:
       1. 使用 Activity.recreate() 而非 finish + start
       2. 启用 Window.setTransitionBackgroundFadeDuration()
       3. 使用 View.setSystemUiVisibility() 平滑过渡

9.2、部分系统应用不响应主题变化

解决方案:
       1. 检查是否正确实现 onConfigurationChanged
       2. 确保在 AndroidManifest 中声明 configChanges
       3. 使用 AppCompatDelegate.setDefaultNightMode()

10、总结

深色模式在 Framework 层的实现涉及多个核心服务的协同:UiModeManager 作为用户接口,ThemeManagerService 负责系统级管理,ResourcesManager 处理资源适配,WindowManagerService 完成窗口更新。理解这些组件的工作机制,有助于开发者更好地实现应用的深色模式适配,提供更流畅的用户体验。

从源码角度看,Android 的深色模式设计体现了良好的分层架构:
       1. 用户层:设置应用提供交互界面
       2. 管理层:UiModeManager 和 ThemeManagerService 协调
       3. 资源层:Resources 系统自动适配
       4. 展示层:Window 和 View 系统渲染

这种设计使得深色模式既能提供系统级的统一体验,又能允许应用灵活定制。

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w