Android 10 暗黑模式适配,你需要知道的一切

2023-11-03

      在 Android 10 里,Dark theme 暗黑模式得到了系统级的支持。暗黑模式不仅酷炫,而且有降低屏幕耗电、在光线较暗的环境中使用更舒适等好处。今天带大家看一下如何适配暗黑模式,本文会从以下几点进行介绍:

  • 动态开启暗黑模式

  • 使用 DayNight 适配暗黑模式

  • 使用 Force Dark 适配暗黑模式

  • Force Dark 系统源码解析

  • 适配流程建议

相信本文会让你对暗黑模式有一个更全面的了解。

动态开启

在 Android 10 系统设置里增加了暗黑模式的开关,但除了系统设置,我们也可以自己动态开启。假如我们项目里面有一个按钮用来开关暗黑模式,可以这样做:

btn.setOnClickListener {
    if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) {
        // 关闭暗黑模式
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
    } else {
        // 开启暗黑模式
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
    }
}


如果当前开启了暗黑模式就关掉,反之开启。你可能还看过另一种 delegate.localNightMode 的写法,同样也是可以生效的,它们的区别在于作用范围不同:

// 作用于当前项目的所有组件
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
// 只作用于当前组件
delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES


另外需要注意的是,在默认情况下,设置暗黑模式会重走 Activity 生命周期,需要重新渲染整个页面,所以不要在 onCreate 里直接设置。如果不想重走生命周期,可以给 Activity 配置 android:configChanges="uiMode",但这样一来就需要在 onConfigurationChanged() 方法里进行手动适配。

NightMode

上面用到了 YES 和 NO 两种暗黑的状态,但其实还不止这两种,暗黑模式一共有这几种状态:

  • MODE_NIGHT_FOLLOW_SYSTEM 跟随系统设置

  • MODE_NIGHT_NO 关闭暗黑模式

  • MODE_NIGHT_YES 开启暗黑模式

  • MODE_NIGHT_AUTO_BATTERY 系统进入省电模式时,开启暗黑模式

  • MODE_NIGHT_UNSPECIFIED 未指定,默认值

由于很多定制系统对省电模式进行了魔改,所以使用 MODE_NIGHT_AUTO_BATTERY 不一定会生效。另外,当 DefaultNightMode 和 LocalNightMode 都是默认值 MODE_NIGHT_UNSPECIFIED 的时候,会作 MODE_NIGHT_FOLLOW_SYSTEM 跟随系统处理。

DayNight

下面要开始对暗黑模式进行适配啦。我们使用 Android Studio 的 Basic Activity 模板创建一个项目,对它进行暗黑模式适配的改造。

DayNight 主题适配

第一步,找到当前项目使用的主题,将默认使用的 Theme.AppCompat.Light 主题修改为 Theme.AppCompat.DayNight:

<style name="AppTheme" parent="Theme.AppCompat.DayNight">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>


第二步,没有第二步了,现在这个项目已经支持暗黑模式了,开启暗黑模式就能看到效果:

是不是很简单,但直觉告诉我们肯定没有这么简单。

硬编码

我们进入 MainActivity 的布局文件 activity_main,可以发现这里面是完全没有使用硬编码的。什么叫硬编码?就是我们平时所说的「写死」。要是我们写死了一个色值,暗黑模式还能生效吗?马上试一下,我们给根布局写死一个白色背景 android:background="#FFFFFF",切换暗黑模式就变成了这样:

可以看到,在写死色值的情况下暗黑模式就失效了。下面看看对于自定义的色值,要如何适配。

value-night

在 colors.xml 里添加一个配置颜色,比如:

<color name="color_bg">#FFFFFF</color>

这个是在普通模式下使用的色值,为了适配暗黑模式,还需要一个在暗黑模式下对应的色值。新建 values-night 目录,并把对应色值配置到这个目录下的 colors.xml 文件。

将根布局的背景颜色修改为 color_bg,这样就能使用我们自己想要的颜色进行适配了:

在暗黑模式下,系统会优先从 night 后缀的目录下找到对应的资源配置。以上就是使用 DayNight 主题进行暗黑模式适配的全部内容了。

DayNight 弊端

一些关于 Android 10 暗黑模式适配的文章到这里就结束了,但其实 DayNight 主题并不是 Android 10 新增的东西,它早在 Android 6.0 就已经出现。虽然它涉及的内容不多,但大家可能也发现了,在实际项目中它的可操作性并不高。首先,使用这种适配方式,要求我们整个项目所有的色值都不能使用硬编码,要做到这一点已经很不容易了,很多项目连统一的设计规范都很难做到。再退一步讲,就算我们所有色值都是使用 xml 配置的,但 colors.xml 里配置了成百上千个色值,我们需要对所有这些色值配置一个对应的暗黑色值,并且要确保它们在暗黑模式下能比较美观的展示。所以,除非项目本身已经有一套严格的设计规范并且严格执行了,否则使用 DayNight 主题适配暗黑模式基本是不具有可操作性的。Android 10 新增的当然不只是一个暗黑模式的开关而已,下面我们看一下 Android 10 有什么新特性供我们适配。

Force Dark

其实我们的需求很明确,就是使用了硬编码也能被适配成暗黑模式。Android 10 新增的 Force Dark 强制暗黑就实现了这个功能。

forceDarkAllowed

还是回到刚才的项目,把背景写死白色,再次来到 styles.xml 的主题配置。这次我们不用 DayNight 主题了,把配置改成如下:

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:forceDarkAllowed">true</item>
</style>


我们把主题换回 Light 亮色主题,至于为什么要用 Light 后面源码部分还会再讲到 另外,重点来了,这里还增加了一个 forceDarkAllowed 的配置,这是 compileSdkVersion 升级到 29 新增的配置,按字面意思就是「开启强制暗黑」。这样就已经完成配置了,在 Android 10 的机器上运行一下,切换暗黑模式,记住这次的背景是写死白色的:

背景被强制转换成黑色了,细心的还会发现,右下角按钮的背景颜色也变深了。Force Dark 这么暴力,连我们写死的色值都改了,虽然方便,但这也给我们一种不安全感。要是 Force Dark 适配出来的颜色不是我们想要的怎么办?我们还能自定义暗黑色值吗?也是可以的。

Force Dark 自定义适配

除了主题新增了 forceDarkAllowed 这个配置,View 里面也有。如果某个 View 的需要使用自定义色值适配暗黑模式,我们需要对这个 View 添加这个配置,让 Force Dark 排除它:

android:forceDarkAllowed="false"

然后在代码里根据当前是否处于暗黑模式,对色值进行动态设置。对于 View 的 forceDarkAllowed,有几点需要注意:

  • 在 View 中使用这个配置的前提是,当前主题开启了 Force Dark

  • 默认值是 true,所以设为 true 和不设是一样的

  • 作用范围是当前 View 以及它所有的子 View

综上可以看出,其实目前并没有很好的 Force Dark 自定义方案。好在 Force Dark 的整体效果没什么大问题,就算要自定义,我们也尽量只对子 View 进行自定义。

Force Dark 源码解析

下面我们看一下源码,看看系统在暗黑模式下是如何对颜色进行转换的。这里仅展示几个关键源码片段,它们之间是如何调用的就不赘述啦。

updateForceDarkMode

看源码首先我们要找到入口,入口就是主题的 forceDarkAllowed 配置,搜索一下可以发现这个配置会在 ViewRootImpl 被用到。相关的说明已经用注释写在代码里了。

// android.view.ViewRootImpl.java


private void updateForceDarkMode() {
    if (mAttachInfo.mThreadedRenderer == null) return;


    // 判断当前是否处于暗黑模式
    boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;


    if (useAutoDark) {
        // 这个是被用来作为默认值用的,这里先不管它,我们后面还会讲到。
        boolean forceDarkAllowedDefault = SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
        TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
        // 判断当前是否为 Light 主题,这也是为什么我们前面要使用 Light 主题。这也很好理解,只有当前主题是亮色的时候,才需要进行暗黑的处理。
        // 判断当前是否允许开启强制暗黑,我们就是靠它找到这个地方的。
        useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
                && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
        a.recycle();
    }


    if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) {
        // TODO: Don't require regenerating all display lists to apply this setting
        invalidateWorld(mView);
    }
}


总结一下,根据这个方法我们可以知道,Force Dark 生效有三个条件:

  • 处于暗黑模式

  • 使用了 Light 亮色主题

  • 允许使用 Force Dark

源码再跟下去,发现调用了 Native 代码。

handleForceDark

下一个关键代码是 RenderNode 的 handleForceDark 函数。RenderNode 是绘制节点,一个 View 可以有多个绘制节点,比如一个 TextView 的文字部分是一个绘制节点,它设置的背景也是一个绘制节点。看一下这个函数做了什么。

// frameworks/base/libs/hwui/RenderNode.cpp


void RenderNode::handleForceDark(android::uirenderer::TreeInfo *info) {
    if (CC_LIKELY(!info || info->disableForceDark)) {
        return;
    }
    // 这个函数看似有点复杂,但其实我们只需要关注 usage 这个参数。
    // usage 有两个取值,Foreground 前景和 Background 背景。
    auto usage = usageHint();
    const auto& children = mDisplayList->mChildNodes;
    if (mDisplayList->hasText()) {
        // 如果当前节点 hasText() 含有文字,那它就是一个 Foreground 前景
        usage = UsageHint::Foreground;
    }
    // 下面的判断都是设为 Background 背景
    if (usage == UsageHint::Unknown) {
        if (children.size() > 1) {
            usage = UsageHint::Background;
        } else if (children.size() == 1 &&
                children.front().getRenderNode()->usageHint() !=
                        UsageHint::Background) {
            usage = UsageHint::Background;
        }
    }
    if (children.size() > 1) {
        // Crude overlap check
        SkRect drawn = SkRect::MakeEmpty();
        for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
            const auto& child = iter->getRenderNode();
            // We use stagingProperties here because we haven't yet sync'd the children
            SkRect bounds = SkRect::MakeXYWH(child->stagingProperties().getX(), child->stagingProperties().getY(),
                    child->stagingProperties().getWidth(), child->stagingProperties().getHeight());
            if (bounds.contains(drawn)) {
                // This contains everything drawn after it, so make it a background
                child->setUsageHint(UsageHint::Background);
            }
            drawn.join(bounds);
        }
    }
    // 根据分类,如果是背景会被设为 Dark 深色,否则是 Light 亮色。
    mDisplayList->mDisplayList.applyColorTransform(
            usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light);
}


这个函数做的就是对当前绘制节点进行 Foreground 还是 Background 的分类。为了保证文字的可视度,需要保证一定的对比度,在背景切换成深色的情况下,需要把文字部分切换成亮色。

transformColor

根据分好的颜色类型,会进入 CanvasTransform 对颜色进行转换处理。这里也是 Force Dark 最核心的地方了。

// frameworks/base/libs/hwui/CanvasTransform.cpp


static SkColor transformColor(ColorTransform transform, SkColor color) {
    switch (transform) {
        case ColorTransform::Light:
            // 转换为亮色
            return makeLight(color);
        case ColorTransform::Dark:
            // 转换为暗色
            return makeDark(color);
        default:
            return color;
    }
}


根据类型调用了对应的函数转换颜色,我们看一下 makeDark 吧。

static SkColor makeDark(SkColor color) {
    Lab lab = sRGBToLab(color);
    float invertedL = std::min(110 - lab.L, 100.0f);
    if (invertedL < lab.L) {
        lab.L = invertedL;
        return LabToSRGB(lab, SkColorGetA(color));
    } else {
        return color;
    }
}

这里把 RGB 色值转换成了 Lab 的格式。Lab 格式含有 L、a、b 三个参数,ab 对应色彩学上的两个维度,不用管它,我们要关注的是里面的 L。L 就是亮度,它的取值范围是 0 - 100,数值越小颜色就越暗,反之就越亮。这篇文章封面的安卓机器人右边颜色就是降低亮度后的效果。回到代码来,这里用 110 减去当前亮度,可以说是对亮度做了取反。至于为什么是用 110 而不是用 100,我猜测是为了避免使用纯黑色。在官方暗黑模式设计规范可以看到,建议使用深灰色作为背景,而不是用纯黑色。

最后比对取反的色值和原色值的亮度,将较暗的那个色值返回。makeLight 函数也是类似的。

static SkColor makeLight(SkColor color) {
    Lab lab = sRGBToLab(color);
    float invertedL = std::min(110 - lab.L, 100.0f);
    if (invertedL > lab.L) {
        lab.L = invertedL;
        return LabToSRGB(lab, SkColorGetA(color));
    } else {
        return color;
    }
}


所以到这里我们发现,其实 Force Dark 强制暗黑转换颜色的规则,或者说是它的本质,就是亮度取反

适配流程建议

如果你的项目 compileSdkVersion 已经升级到 29,那现在就可以开启 Force Dark 适配暗黑模式了。但很多项目要升级到 29 还有一段路要走,我们有没有办法提前适配呢?

Debug Force Dark

回到我们开始看源码的地方:

boolean forceDarkAllowedDefault = SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);
TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
        && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);


当取不到 Theme_forceDarkAllowed 的时候,会取 DEBUG_FORCE_DARK 作为默认值,在哪里可以开启这个 DEBUG_FORCE_DARK 呢?在 Android 10 的开发者选项里面,可以发现多了一个这样的选项:

这里的「强制启用 SmartDark 功能」就是 DEBUG_FORCE_DARK 的开关,虽然我们看了源码都知道它也没有多智能。开启后会对所有项目生效,这样就可以提前用 Force Dark 进行适配了。

适配流程

开启 Force Dark 后大概率会发现一些有问题的图片资源,比如带有固定背景的 icon 等。如果项目有适配暗黑模式的计划,个人建议可以按以下几步走:

  1. 开发者选项开启「强制启用 SmartDark」

  2. 替换有问题的资源,进行初步适配

  3. compileSdkVersion 升级到 29

  4. 开启 Force Dark

  5. 和设计师沟通,对部分控件单独适配

总结

使用 DayNight 主题可以实现暗黑模式的适配,但这种方法在实际项目中可操作性不高。Android 10 新增的暗黑模式特性叫 Force Dark 强制暗黑,只需给主题添加一个允许开启的配置即可。Force Dark 的实现方式是降低背景亮度,提高字体亮度,本质是对色值进行亮度取反。最后,在 Android 10 的设备上,可以开启开发者选项中的「强制启用 SmartDark」,提前用 Force Dark 适配。

妥妥的。


作者:NanBox
链接:https://juejin.im/post/5ecf8c9f51882542f871d7a6

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

Android 10 暗黑模式适配,你需要知道的一切 的相关文章

  • Windows 常用快捷键

    常用快捷键 Ctrl C 复制选定项 Ctrl X 剪切选定项 Ctrl V 粘贴选定项 Ctrl Z 撤消操作 Ctrl Y 重做操作 Ctrl S 保存 Ctrl A 选择文档或窗口中的所有项目 Alt Tab 在打开的应用之间切换 W
  • Qt Utils : To-Do

    Qt Creator自带的todo插件工具 真心舒爽 特别是对于我这种记不住三天前自己写的shit mountain的 渣渣CXY来讲 边撸代码边注释 快速查阅Task 非常重要 1 上效果图 2 工具使用 1 勾选使用插件 重启Qt Cr
  • 7-32 统计MOOC证书

    本题要求编写程序 输入N个学生的MOOC成绩 统计优秀 合格证书的数量 以及没有获得证书的数量 学生修读程序设计MOOC 85分及以上获得优秀证书 不到85分但是60分及以上获得合格证书 不到60分则没有证书 输入格式 输入在第一行中给出非
  • 如何安装新的PHP扩展模块

    一 phpize方式 该方法用于安装php源码ext目录中没有的扩展 1 下载源码 2 解压并进入扩展目录 3 执行phpize 4 执行 configure 5 make make install 6 在php ini 文件中添加 ext
  • JAVA识别复杂验证码+图像处理

    先对验证码进行简单的处理噪点和纯色 例未曾处理的图片 public static void main String args throws Exception 源文件 String picName C Users syxy101 Deskt
  • 您无权输入许可证密钥,请请使用系统管理员账户重试

    转载于 https www cnblogs com java2016 p 5448093 html
  • Android 解决Retrofit请求数据,数据过多,返回json数据乱码问题

    同一个POST请求返回的数据 有时候乱码 有时候不乱码 最后发现 数据量过多就会出现乱码 直接使用原生HttpUrlConnection请求不会产出乱码 我猜测就是框架配置的问题 然后在网上寻找解决方面发现一个帖子类似我这种问题 地址 问题
  • 小米9 MIUI12.5 红米 K40s MIUI13.0.10 安装谷歌框架

    前言 由于更换了小米9手机后 我想重新安装谷歌框架的 发现这谷歌框架安装不上了 下载第三方安装框架工具也是不行 然后看到一篇文章说小米9手机自带有个GMS服务框架 然后我试了一下还真的可以 所以分享一下 如果文章没了说明我已经进去了 设备
  • 【OJ刷题

    欢迎关注微信公众号 Python小灶 和我一起每天学习Python新知识 还可添加博主Vx yf03064131 方便一起交流学习 或者B站搜索 有只小新 文章目录 多数组合并 数组排序 最长的指定瑕疵度的元音字串 20210909 总共三
  • 2016的诗和远方

    当生活被眼前的苟且蒙住了双眼 其实你所希冀的远方 就在那噼啪敲击的键盘里 渗入脑海实现想法的一行行代码中 眼看一年就要结束了 坐在公司的办公区里 窗外霓虹灯五光十色 办公楼鳞次栉比 恍惚想起了这一年充满波折又熠熠生辉的日子 却又是欲买桂花同
  • 新建文件夹命令 linux,linux创建文件夹命令是什么

    linux创建文件夹命令是mkdir 语法为 mkdir 选项 参数 其中Z为设置安全上下文 当使用SELinux时有效 version显示版本信息 本文操作环境 linux2 6 32系统 DELL G3电脑 Linux中 mkdir 创
  • CEVA RivieraWaves™ Wi-Fi IP

    https www ceva dsp com product rivierawaves wi fi platforms OVERVIEW The RivieraWaves Wi Fi IP family is a comprehensive
  • 提交本地项目到GitHub

    文章目录 1 下载git 1 1 通过homebrew安装Git 1 2 通过Xcode安装 2 创建ssh key 配置git 3 提交本地项目到GitHub 说明 该博文参考这篇文章和这段视频 1 下载git 1 1 通过homebre
  • 全面了解Maven依赖范围

    Maven依赖范围 翻译原文详见 Maven Dependency Scopes 1 总览 Maven 是 Java 生态系统中最流行的构建工具之一 其核心特性之一是依赖管理 Maven is one of the most popular
  • vue应用的简单例子、$.get()方法及页面获取url里面的参数

    vue应用的简单例子 get 方法及页面获取url里面的参数 页面 要先引入vue的js div 123 hospital name div
  • C++学习笔记:函数绑定器(bind用法)

    绑定器bind总览 bind用于绑定可调用 Callable 对象 函数对象 指向函数指针 到函数引用 指向成员函数指针或指向数据成员指针 和其参数 返回值为绑定成功后的函数对象 在正式开始绑定器前 先进行一下知识补充 补充1 函数对象 函
  • android4.0 ActionBar API

    ActonBar介绍 ActionBar取代了传统的标题栏 title 其在activity位置就是title原有的位置 在activity的顶部 ActionBar上默认情况下包括了应用 app 的logo logo的位置在ActionB
  • 漏洞修复中常用命令

    1 rpm Uvh rpm rpm qa grep 文件名查看版本 2 yum update 更新所有可以更新版本的软件包 rpm qa XXX 查看XXX版本信息 3 yum update y yum install y yum loca
  • python,使用字典(哈希表)记录数组中每个数字以及对应出现的次数

    list1 1 2 2 3 2 4 3 5 5 6 dic1 for i v in enumerate list1 if v not in dic1 如果数字不在哈希表中 字典的key 则次数为1 dic1 v 1 else 把之前的次数
  • linux欧拉强制修改root密码,openEuler 20.03 LTS安装图文教程

    本文以图文的方式介绍安装openEuler 20 03 LTS的方法 以光盘安装为例 其他安装方式除在启动安装时的引导方式不同外 待启动安装后则安装流程相同 在安装开始前 需要保证服务器启动选项为光驱优先 openEuler 20 03 L

随机推荐

  • mapbox的popup里使用vue组件

    问题 在mapbox官网中 他的popup实例是这样的 var popup new mapboxgl Popup offset popupOffsets className my class setLngLat e lngLat setHT
  • 第八章 ⾼并发下的微服务架构存在的问题和解决⽅案

    1 并发下的微服务存在的问题 并发下存在的问题 微服务拆分多个系统 服务之间互相依赖 可能会由于 系统负载过 突发流量或者 络等各种异常情况 导致 服务不可 核 思想 向失败编程 不要外界影响 不被请求拖垮 2 并发下的微服务容错 案 限流
  • 光猫怎么设置wifi 光猫怎么设置wifi密码

    怎么设置电信光纤猫的无线网络 电信光纤猫安装好后 请将网线口接入光纤猫的一个网口 如网口1 网线另一端接入电脑网口 查看网络链接状态 确保成功接入网络 使用默认地址进入光纤猫设置页面 一般默认地址为192 168 1 1 用户名以及密码可在
  • fastboot一键进入9008_【高通9008】究竟是怎么一回事?

    转自 河北阮咸科技有限公司 这里说的高通 是指采用高通品牌CPU的安卓手机 高通就是近两年和华为争5G标准的那个美国公司 国内众多的品牌 如 小米 oppo vivo 华为 对 华为也有一部分机器采用了高通的CPU 只要是高通的CPU就会有
  • jsp导入所需要的JavaBean方法

    在jsp中可以使用指令导入所需要的包 或者使用
  • OSTU算法

    OSTU算法目的就是计算出一连通区域的阈值 然后对该区域二值化 Ostu算法是一种用于二值化最佳阈值的选取方法 基本原理是根据阈值T将图像中的像素点分为C1和C2两类 不断的调整阈值T之后若此时两类之间存在最大的类间方差 那么此阈值即是最佳
  • Flutter开发报错uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library

    文章目录 问题描述 问题原因 解决方法 gradle文件介绍 项目级别的build gradle 模块级别的build gradle 问题描述 今天导入一个新项目时报错 报错内容如下 uses sdk minSdkVersion 16 ca
  • 吴恩达机器学习(六)线性回归的梯度下降

    线性回归的梯度下降 线性回归模型 线性假设函数 平方差代价函数 梯度下降算法可以优化J 0 1 最小平方差代价函数 实现好的梯度下降算法的关键 在于在导数项 线性回归的代价函数 形状总是凸函数 convex 只有一个全局最优解 在梯度下降的
  • 完整的性能测试流程

    前言 本篇文章带大家一起学习性能测试 1 使用jmeter工具进行接口的性能压测 2 熟练使用jmeter工具 3 针对项目接口进行压测 性能测试的流程和操作的过程介绍 4 分析调优 拓展部分 一 关于性能测试的理论介绍 为什么要进行性能测
  • MyEclipse的properties配置文件中文显示为unicode问题解决方法

    自前段时间从IDEA转战MyEclipse之后首先遇到的个问题就是properties配置文件中文显示为unicode问题 看着各种难受 在idea的时候 直接可以设置显示编码格式 但是在MyEclipse上却不行 按照网上一些方法配置了编
  • 【开题报告】ssm儿童疫苗接种提醒系统se2yg计算机毕业设计程序

    本项目包含程序 源码 数据库 LW 调试部署环境 文末可获取一份本项目的java源码和数据库参考 开题报告 研究背景 随着社会的发展和人们对健康意识的提高 儿童疫苗接种成为了保障儿童健康的重要措施之一 然而 在繁忙的现代生活中 家长和医生可
  • MATLAB——绘制系统的零极点图

    题目1 已知系统函数 H s s
  • @Setter与@Getter注解无效,以及idea无法搜索插件的解决方案

    原因 1 lombok插件未安装 2 lombok插件损坏 解决方案 重新安装lombok插件 步骤 进入idea点击File gt Settings gt 搜索点击Plugins 进入插件界面 在搜索框中输入lombok安装 若无法搜索到
  • Gradle 复制文件 无知的菜墩

    Gradle 复制文件 很多大佬都是直接贴出如下代码 简单说就是 task 直接使用 from into include 等方法 然而直接复制下来之后 过了俩小时零一秒钟后依然无法使用 一直不生效 task nestedSpecs type
  • Go Facade外观(门面)设计模式

    动机 Motivation 上述A方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合 随着外部客户程序和各子系统的演化 这种过多的耦合面临很多变化的挑战 如何简化外部客户程序和系统间的交互接口 如何将外部客户程序的演化和内部子系
  • hbuilderx自定义常用代码块

    apipost body let res await this http post 1 if res code 200 2 else this toast res msg prefix apipost project uni app sco
  • hdu 5831 Rikka with Parenthesis II 2016 Multi-University 8

    Problem acm hdu edu cn showproblem php pid 5831 题意 给个括号序列 问能不能通过一次把两个不同位置的符号交换的操作 使得序列里的所有括号左右配对合法 分析 左括号进栈 如果是右括号而且栈顶是左
  • Linux性能监控命令_sar & 自动保存30天历史信息

    简介 sar命令将操作系统中选定的累积活动计数器的内容写入标准输出 计费系统根据 count 和 interval参数中的值 以秒为单位 按照指定的时间间隔写入指定次数的信息 目录 1 语法 1 1 常用参数 2 常见用法 2 1 监控CP
  • HTTP->WebRTC演进路径

    first HTTP Pre AJAX 原始web 一页里发送请求后才返回另一页 如Geocities second AJAX 2004 更新页面不需要刷新 如GMail third Web Sockets 2008 页面能建立双向通信 通
  • Android 10 暗黑模式适配,你需要知道的一切

    在 Android 10 里 Dark theme 暗黑模式得到了系统级的支持 暗黑模式不仅酷炫 而且有降低屏幕耗电 在光线较暗的环境中使用更舒适等好处 今天带大家看一下如何适配暗黑模式 本文会从以下几点进行介绍 动态开启暗黑模式 使用 D