当前位置: 首页 > news >正文

Jetpack太香了,让开发效率提升了不少

作者:Jingle_zhang

第三方App使用Jetpack等开源框架非常流行,在Gradle文件简单指定即可。然而ROM内置的系统App在源码环境下进行开发,与第三方App脱节严重,采用开源框架的情况并不常见。但如果系统App也集成了Jetpack或第三方框架,开发效率则会大大提高。

前言

系统App开发者,很少采用Jetpack 以及第三方框架的原因主要有几点:

  1. 导入麻烦:有的框架过于庞大,可能依赖的库比较多,编译文件的构建比较繁琐,没有gradle那么智能

  2. 功能单一:系统App注重功能性,业务逻辑较少,依赖庞大库文件的场景不多

  3. license风险:引用第三方框架的话,需要特别声明license ,会尽量避免采用

但对于功能复杂,架构庞大的系统App而言,集成第三方框架显得尤为必要。比如Android系统里最核心的App SystemUI,就采用了知名的DI框架Dagger2 。Dagger2的引入使得功能庞杂的SystemUI管理各个依赖模块变得游刃有余。

SystemUI将Dagger2集成的方式给了我启发,探索和总结了Android 源码中如何配置Jetpack 以及第三方库,希望能够帮到大家。

源码编译说明

与Gradle不同,源码环境里的编译构建都是配置在.mk或者.bp文件里的,配置起来较为繁琐。

.bp文件::Android.bp是用来替换Android.mk的配置文件,它使用Blueprint框架来解析。Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong则是专为Android编译而设计的工具,Blueprint只是解析文件的形式,而Soong则解释内容的含义,最终转换成Ninja文件。下文bp 就是指.bp的文件

**注意:**以下基于Android 11上进行的演示,Android 10及之前部分Jetpack框架没有集成进源码,需留意

gradle切换到bp

gradle和bp的对比

看一个使用aar和注解库的例子。

看一个AndroidStudio(以下简称AS)下build.gradle 文件里包的导入代码:

dependencies {implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'com.google.android.material:material:1.2.1'implementation 'androidx.constraintlayout:constraintlayout:2.0.1'//roomdef room_version = "2.3.0"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version"
}

ROM环境里的编译依赖.bp 配置如下:

android_app {......static_libs: [        "androidx.appcompat_appcompat",        "com.google.android.material_material",        "androidx-constraintlayout_constraintlayout",        "androidx.room_room-runtime",    ],plugins: ["androidx.room_room-compiler-plugin"],......
}

导入关键字的差异

依赖文件里的导入关键字:

在AS和AOSP里面导入包的关键字有些差异,又分为两种情况。

build.gradle.bp
代码库implementationstatic_libs
注解使用的库annotationProcessorplugins

引入库文件(libs):比较常见。引入的方式有多种。下文会讲具体的几种方式。

引入注解库:比较流行,源码中使用比较繁琐,下文会重点讲解。

库文件的导入规则

眼尖的同学已经看出规律了

如:implementation ‘androidx.appcompat:appcompat:1.2.0’

bp 文件中:androidx.appcompat_appcompat,将“:” 改为 “”即可,不需要加版本号。其实就是group 与 name 中间用“”连接,基本上符合上述规则,当然也有特殊

注解库的导入规则

如今框架流行注解编程。

gradle 配置:annotationProcessor “androidx.room:room-compiler:$room_version”

bp 中就需要使用到plugins,对应配置plugins: [“androidx.room_room-compiler-plugin”]

根据jar 包的规则,那plugin 命名应该是“:” 改为 ”_" version+“-plugin” 。

SystemUI 使用Dagger2配置 plugins: [“dagger2-compiler-2.19”],所以命名规则并不是上文猜测的那样。

那如何确定Jetpack框架的名称呢?

确定Jetpack框架的名称

源码编译,所有的内容和都在源码中,都需要在源码环境中寻找。

以Room 为例

在prebuilts/sdk/current/androidx/Android.bp 配置了引入jar包 中有如下配置

android_library {name: "androidx.room_room-runtime",//名称......manifest: "manifests/androidx.room_room-runtime/AndroidManifest.xml",//配置manifaststatic_libs: [//两个room库文件,三个依赖的库文件"androidx.room_room-runtime-nodeps","androidx.room_room-common","androidx.sqlite_sqlite-framework","androidx.sqlite_sqlite","androidx.arch.core_core-runtime",],
}

插件配置在prebuilts/sdk/current/androidx/JavaPlugins.bp

java_plugin {name: "androidx.room_room-compiler-plugin",//名称static_libs: [//1个room库文件,1个依赖的库文件"androidx.room_room-compiler","kotlin-reflect"],processor_class: "androidx.room.RoomProcessor",//需要指定处理的类
}

注意:AS 开发 并不需要配置 “processor_class”,我反编译了room-compiler,找到了RoomProcessor.java.(AS 为什么不需要指定,我这里我就不研究了)

看下图,META-INF/services/javax.annotation.processing.Processor 文件中配置了RoomProcessor.java(就按照这个文件配置就可以了)

如何确定源码中哪些jetpack 库可以使用呢?

在Android.bp 中搜索,或者看androidx目录下包含了什么

prebuilts/sdk/current/androidx/m2repository/androidx$ ls

导入第三方的开源框架

以上讲的是引入Jetpack相关jar包,其他常见的是否包含呢?如Glide,它是不属于androidx 的

第三方库,Android 源码中整理就不算好了,使用比较乱。下面我梳理下

导入下载的jar包

大家最常用的,把 jar 包 放到 libs,就可以了(当然,比较简单,与其他库关联较少可以采用此种方式)

java_import {name: "disklrucache-jar",jars: ["disklrucache-4.12.0.jar"],sdk_version: "current",
}
android_library_import {name: "glide-4.12.0",aars: ["glide-4.12.0.aar"],sdk_version: "current",
}
android_library_import {name: "gifdecoder-4.12.0",aars: ["gifdecoder-4.12.0.aar",],sdk_version: "current",
}
android_library_import {name: "exifinterface-1.2.0",aars: ["exifinterface-1.2.0.aar",],sdk_version: "current",
}

android_app {......static_libs: ["disklrucache-jar","glide-4.12.0","gifdecoder-4.12.0","exifinterface-1.2.0"],
}

导入AOSP内置的jar包

常用第三方放在了prebuilts/tools/common/m2/repository/下面包含了很多库文件,如Glide,Okhttp,但比较尴尬的是,.bp文件并没有写好。应用需要自己编写,编写方式可以参考上文。

以后google应该会把 external 下 的整合到这个里面,可以关注下prebuilts/tools/common/m2/repository 中Android.bp文件的变化。

如:prebuilts/maven_repo/bumptech/Android.bp

java_import {name: "glide-prebuilt",jars: ["com/github/bumptech/glide/glide/4.8.0/glide-4.8.0.jar","com/github/bumptech/glide/disklrucache/4.8.0/disklrucache-4.8.0.jar","com/github/bumptech/glide/gifdecoder/4.8.0/gifdecoder-4.8.0.jar",],jetifier: true,notice: "LICENSE",
}

Android.bp 直接用"glide"了

static_libs: ["glide-prebuilt"],

导入jar包源码

external 下面 很多第三方库的源码,如Glide的源码,目录为external/glide/

android_library {name: "glide",srcs: ["library/src/**/*.java","third_party/disklrucache/src/**/*.java","third_party/gif_decoder/src/**/*.java","third_party/gif_encoder/src/**/*.java",],manifest: "library/src/main/AndroidManifest.xml",libs: ["android-support-core-ui","android-support-compat","volley",],static_libs: ["android-support-fragment",],sdk_version: "current",
}复制代码

App 的Android.bp 直接用"glide"了

static_libs: ["glide"],

以上三种方式都是引入 Android 中源码存在的。不存在怎么办,Android源码 不像 AS,连上网,配置下版本号就可以下载。

内置新的Jetpack框架

引入第三方库文件方式,方式一:aar包导入。就可以。但这里不讨论,找些复杂的,包含annotationProcessor(bp 中的plugin) 。Hilt 是 Google 相对较新的框架。

Hilt基于Dagger2开发,又针对Android进行了专属的DI优化。

所以在导入Dagger2和它的依赖文件之外还需要导入Hilt专属的一堆库和依赖文件。

1. 获取框架的库文件

一般来说AS里导入完毕的目录下即可获取到对应的库文件,路径一般在 :C:\Users\xxx.gradle\caches\modules-2\files-2.1\com.google.dagger\hilt-android

2. 确定额外的依赖文件

为什么需要额外的依赖文件?

完全依赖AS开发可能不知道,导入的包的同时可能引入其他的包。

如Hilt的是在dagger2基础上开发,当然会引入Dagger2,

使用注解,需要javax.annotation包。

Dagger2,javax.annotation 在Gradle 自动下载好的,非项目中明确配置的,我们称之为依赖包。

使用Gradle 自动下载,都会有pom 文件。“dependency”,表示需要依赖的jar 包,还包含了版本号等

如:hilt-android-2.28-alpha.pom

`<dependency>``<groupId>com.google.dagger</groupId>``<artifactId>dagger</artifactId>` //依赖的dagger2`<version>2.28</version>`//dagger2的版本
`</dependency>`
`<dependency>``<groupId>com.google.dagger</groupId>` `<artifactId>dagger-lint-aar</artifactId>``<version>2.28</version>`
`</dependency>`
`<dependency>``<groupId>com.google.code.findbugs</groupId>``<artifactId>jsr305</artifactId>``<version>3.0.1</version>`
`</dependency>`
......

3. 导入需要的依赖文件

比如SystemUI,已经导入了一些文件,只要导入剩余的文件即可。

一般常用的 源码中都是存在的,决定copy 之前,可以看下先源码中是否存在,存在可以考虑使用。

当然也有例外,如Hilt 我依赖的是源码中dagger2是2.19 版本,编译中报错,没有找到dagger2 中的class,反编译jar确实不存在,使用2.28 的dagger 版本,问题就解决了。所以说可能存在库文件版本较老的情况。

以下就是新增的文件夹,其中manifests 后文中有讲。

    manifests/ repository/com/google/dagger/dagger-compiler/2.28/repository/com/google/dagger/dagger-producers/2.28/repository/com/google/dagger/dagger-spi/2.28/repository/com/google/dagger/dagger/2.28/repository/com/google/dagger/hilt-android-compiler/repository/com/google/dagger/hilt-android/

4. 编写最终的bp文件

这一步就是把依赖的包,关联起来,根据上文的 pom 文件。

  • 配置dagger2 2.28 的jar
java_import {name: "dagger2-2.28",jars: ["repository/com/google/dagger/dagger/2.28/dagger-2.28.jar"],host_supported: true,}
  • 配置 dagger2-compiler 2.28 的jar (annotationProcessor 依赖的jar包)
java_import_host {name: "dagger2-compiler-2.28-import",jars: ["repository/com/google/dagger/dagger-compiler/2.28/dagger-compiler-2.28.jar","repository/com/google/dagger/dagger-producers/2.28/dagger-producers-2.28.jar","repository/com/google/dagger/dagger-spi/2.28/dagger-spi-2.28.jar","repository/com/google/dagger/dagger/2.28/dagger-2.28.jar","repository/com/google/guava/guava/25.1-jre/guava-25.1-jre.jar","repository/com/squareup/javapoet/1.11.1/javapoet-1.11.1.jar","repository/com/google/dagger/dagger-google-java-format/1.6/google-java-format-1.6-all-deps.jar",],
}
  • 配置dagger2 的 plugin (annotationProcessor)
java_plugin {name: "dagger2-compiler-2.28",static_libs: ["dagger2-compiler-2.28-import","jsr330",],processor_class: "dagger.internal.codegen.ComponentProcessor",generates_api: true,
}
  • 配置 hilt 依赖的aar包
android_library_import {name: "hilt-2.82-nodeps",aars: ["repository/com/google/dagger/hilt-android/2.28-alpha/hilt-android-2.28-alpha.aar"],sdk_version: "current",apex_available: ["//apex_available:platform","//apex_available:anyapex",],min_sdk_version: "14",static_libs: ["dagger2-2.28","jsr305","androidx.activity_activity","androidx.annotation_annotation","androidx.fragment_fragment",],}
  • 配置hilt 的包

    android_library 表示 aar 包,所以必须要配置manifests ,在上文中多出的manifasts文件夹中 放的就是这个文件,AndroidManifest.xml来自hilt-android-2.28-alpha.aar 中

android_library {name: "hilt-2.82",manifest: "manifests/dagger.hilt.android/AndroidManifest.xml",static_libs: ["hilt-2.82-nodeps","dagger2-2.28"],......
}
  • 配置 hilt-compiler 2.82 jar包
java_import_host {name: "hilt-compiler-2.82-import",jars: ["repository/com/google/dagger/dagger-compiler/2.28/dagger-compiler-2.28.jar","repository/com/google/dagger/dagger-producers/2.28/dagger-producers-2.28.jar","repository/com/google/dagger/dagger-spi/2.28/dagger-spi-2.28.jar","repository/com/google/dagger/dagger/2.28/dagger-2.28.jar","repository/com/google/guava/guava/25.1-jre/guava-25.1-jre.jar","repository/com/squareup/javapoet/1.11.1/javapoet-1.11.1.jar","repository/com/google/dagger/dagger-google-java-format/1.6/google-java-format-1.6-all-deps.jar","repository/com/google/dagger/hilt-android-compiler/2.28-alpha/hilt-android-compiler-2.28-alpha.jar","repository/javax/inject/javax.inject/1/javax.inject-1.jar"],
}
  • 配置hilt的 plugin (annotationProcessor)

    反编译查看需要配置的Processer

好吧,看到上图我傻眼了,11个。下文代码我只贴了一个,需要写11个,其他省略。

java_plugin {name: "hilt-compiler-2.82",static_libs: ["hilt-compiler-2.82-import","jsr330",],processor_class: "dagger.hilt.processor.internal.root.RootProcessor",generates_api: true,
}
  • 项目中引用
    `static_libs: [``"androidx-constraintlayout_constraintlayout",``"androidx.appcompat_appcompat",``"com.google.android.material_material",``"androidx.room_room-runtime",``"androidx.lifecycle_lifecycle-viewmodel",``"androidx.lifecycle_lifecycle-livedata",``"hilt-2.82",``"jsr330"``],``plugins: ["androidx.room_room-compiler-plugin",``"hilt-compiler-2.82",``"hilt-compiler-2.82-UninstallModulesProcessor",``"hilt-compiler-2.82-TestRootProcessor",``"hilt-compiler-2.82-DefineComponentProcessor",``"hilt-compiler-2.82-BindValueProcessor",``"hilt-compiler-2.82-CustomTestApplicationProcessor",``"hilt-compiler-2.82-AndroidEntryPointProcessor",``"hilt-compiler-2.82-AggregatedDepsProcessor",``"hilt-compiler-2.82-OriginatingElementProcessor",``"hilt-compiler-2.82-AliasOfProcessor",``"hilt-compiler-2.82-GeneratesRootInputProcessor",``],`
  • 编译确认

    编译失败了!看到报错,我的心也凉了。需要配置Gradle 插件。bp 可以配置Gradle插件?

    看了下com/google/dagger/hilt-android-gradle-plugin/,但是并不清楚bp 怎么配置,在源码里,只知道一处:prebuilts/gradle-plugin/Android.bp,但并没有尝试成功。有兴趣的同学,可以研究下。

    而且hilt-android-gradle-plugin 的jar包,依赖包 至少十几个。

public class MainActivity extends AppCompatActivity { ^ Expected @AndroidEntryPoint to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.

public class MainFragment extends BaseFragment { ^ Expected @AndroidEntryPoint to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.

public class AppApplication extends Application { ^ Expected @HiltAndroidApp to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.

虽然Hilt引入失败,但是整个过程我觉得有必要分享一下,给大家一些导入新框架的参考。

源码环境里集成开源框架的流程

常用开源框架的对照表

build.gradleAndroid.bpAOSP源码位置
androidx.appcompat:appcompatandroidx.appcompat_appcompat/sdk/current/androidx/Android.bp
androidx.core:coreandroidx.core_coreprebuilts/sdk/current/androidx/Android.bp
com.google.android.material:materialcom.google.android.material_materialprebuilts/sdk/current/extras/material-design-x/Android.bp
androidx.constraintlayout:constraintlayoutandroidx-constraintlayout_constraintlayoutprebuilts/sdk/current/extras/constraint-layout-x/Android.bp
androidx.lifecycle:lifecycle-livedataandroidx.lifecycle_lifecycle-livedataprebuilts/sdk/current/androidx/Android.bp
androidx.lifecycle:lifecycle-viewmodelandroidx.lifecycle_lifecycle-viewmodelprebuilts/sdk/current/androidx/Android.bp
androidx.recyclerview:recyclerviewandroidx.recyclerview_recyclerviewprebuilts/sdk/current/androidx/Android.bp
androidx.annotation:annotationandroidx.annotation_annotationprebuilts/sdk/current/androidx/Android.bp
androidx.viewpager2:viewpager2androidx.viewpager2_viewpager2prebuilts/sdk/current/androidx/Android.bp
androidx.room:room-runtimeandroidx.room_room-runtimeprebuilts/sdk/current/androidx/Android.bp
glideglide-prebuiltprebuilts/maven_repo/bumptech/Android.bp
gsongson-prebuilt-jarprebuilts/tools/common/m2/Android.bp
Robolectric相关Robolectric相关prebuilts/tools/common/m2/robolectric.bp

经验总结

1、build.gradle 需要配置 额外插件的,如hilt、databinding viewbinding 不建议使用源码编译。

2、建议使用 AOSP 源码 中 bp 已经配置好的。这样就可以直接使用了。

3、jetpack 包引入或者androidx 引入,建议先prebuilts/sdk/current/androidx 下寻找配置好的bp 文件

4、非androidx ,建议先在prebuilts/tools/common/m2下寻找寻找配置好的bp 文件

5、文章中的例子都是prebuilts目录下配置,项目中使用,也可以配置在项目中,都是可以的。

相关文章:

Jetpack太香了,让开发效率提升了不少

作者&#xff1a;Jingle_zhang 第三方App使用Jetpack等开源框架非常流行&#xff0c;在Gradle文件简单指定即可。然而ROM内置的系统App在源码环境下进行开发&#xff0c;与第三方App脱节严重&#xff0c;采用开源框架的情况并不常见。但如果系统App也集成了Jetpack或第三方框架…...

【软考中级信安】第四章--网络安全体系与网络安全模型

1.网络安全体系概述1.1 网络安全体系概念网络安全体系&#xff1a;是网络安全保障系统的最高层概念抽象&#xff0c;是由各种网络安全单元按照一定的规则组成的&#xff0c;共同实现网络安全的目标。1.2 网络安全体系特性整体性&#xff1a;网络安全单元按照一定规则&#xff0…...

四、GC分析内存调优

文章目录&#xff08;持续更新中... ...&#xff09;GC分析&内存调优工具篇JDK自带的工具jconsolejvisualvm第三方工具arthas&#xff08;重要&#xff09;jprofiler&#xff08;收费的&#xff09;MAT、GChisto、gcviewer、GC Easy&#xff08;待完善&#xff09;参数、命…...

如何快速开发一套分布式IM系统

架构说明&#xff1a; 1&#xff09;CIM 中的各个组件均采用 SpringBoot 构建&#xff1b;2&#xff09;采用 Netty Google Protocol Buffer 构建底层通信&#xff1b;3&#xff09;Redis 存放各个客户端的路由信息、账号信息、在线状态等&#xff1b;4&#xff09;Zookeeper …...

W806|CKLINK LITE|调试|elf文件模板|CSDK|Debug|学习(4):CKLINK调试W806

一、硬件连接 接线方式 &#xff08;连线颜色供参考&#xff0c;本例中采用图示颜色&#xff09;&#xff1a; 注意&#xff1a;CKLINK LITE的3V3须与W806的3V3相连&#xff0c;或者给W806开发板单独供电&#xff0c;两种方式均可。 ​ 否则&#xff0c;会提示“the referenc…...

【100个 Unity实用技能】 ☀️ | 脚本无需挂载到游戏对象上也可执行的方法

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…...

「IT女神勋章」挑战赛#

缓存 本地缓存 本地缓存为了保证线程安全问题&#xff0c;一般使用ConcurrentMap的方式保存在内存之中 分布式缓存。 常见的分布式缓存则有Redis&#xff0c;MongoDB等。 一致性&#xff1a;本地缓存由于数据存储于内存之中&#xff0c;每个实例都有自己的副本&#xff0c…...

易优cms user 登录注册标签

user 登录注册标签 user 登录注册入口标签 [基础用法] 标签&#xff1a;user 描述&#xff1a;动态显示购物车、登录、注册、退出、会员中心的入口&#xff1b; 用法&#xff1a; {eyou:user typeuserinfo} <div id"{$field.htmlid}"> …...

源码安装Redis 7.0.9并且systemctl管理

以下是在/usr/local/redis中通过源代码安装Redis 7.0.9并将其加入systemctl管理的步骤&#xff1a; 首先&#xff0c;下载Redis 7.0.9源代码包&#xff1a; wget https://download.redis.io/releases/redis-7.0.9.tar.gz解压缩Redis源代码包&#xff1a; tar xzf redis-7.0.9…...

编写程序:有92号和95号汽油可以选择,选择你需要的汽油,并输入需要加油的升数,点击按钮“`计算总价钱`“在div中可以得到你所需要支付的价格

需求&#xff1a; 有92号汽油和95号可以选择&#xff0c;选择你需要的汽油&#xff0c;并输入需要加油的升数&#xff0c;点击按钮"计算总价钱"在div中可以得到你所需要支付的价格。结构如下图所示&#xff1a; 详细代码如下&#xff1a; <!DOCTYPE html> &l…...

参考文献去哪里查找,参考文献标准格式是什么

1、参考文献类型&#xff1a; 普通图书[M]、期刊文章[J]、报纸文章[N]、论文集[C]、学位论 文[D]、报告[R]、标准[s]、专利[P]、数据库[DB]、计算机程序[CP]、电 子公告[EB]、联机网络[OL]、网上期刊[J&#xff0f;OL]、网上电子公告[EB&#xff0f;OL]、其他未 说明文献[z]。…...

WIFI标签操作步骤

1. 打开并设置手机WIFI热点&#xff0c;设置SSID为ESL&#xff0c;密码为123456789&#xff08;如下图&#xff09; ​ 2. 运行APP&#xff0c;设置要接入的WIFI名称密码等信息&#xff08;如下图&#xff09; ​ 3. 长按背面按键&#xff08;长按2-3秒&#xff09;&#xff0c…...

【Hello Linux】命令行解释器

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;使用进程的基础知识和进程控制知识做出一个简单的shell程序 命令行解释器介绍搭架子缓冲区获取命令如何从标准输入中获取字符串解析命令…...

开源一个通用的 HTTP 请求前端组件

像 Postman 这样可视化的 HTTP 请求工具是调试 API 不可或缺的利器。Postman 虽好但也越来越重&#xff0c;而且如果要整合到其他工具中&#xff0c;显然 Postman 又不是一个可行的方案。于是我想打造一个简单的前端组件&#xff08;widget&#xff09;&#xff0c;它是一个标准…...

等保测评机构资质申请条件是什么?个人可以申请吗?

最近看到不少网友在问&#xff0c;等保测评机构资质申请条件是什么&#xff1f;个人可以申请吗&#xff1f;今天我们小编就来给大家详细回答一下。 等保测评机构资质申请条件是什么&#xff1f;个人可以申请吗&#xff1f; 【回答】&#xff1a;首先需要明确一点的是&#xf…...

android 卡顿、ANR优化(1)屏幕刷新机制

前言&#xff1a; 本文通过阅读各种文章和源码总结出来的&#xff0c;如有不对&#xff0c;还望指出 目录 正文 基础概念 视觉暂留 逐行扫描 帧 CPU/GPU/Surface&#xff1a; 帧率、刷新率、画面撕裂 画面撕裂 Android屏幕刷新机制的演变 单缓存&#xff08;And…...

Landsat8中*_MTL.txt文件详解

01 什么是*_MTL.txt文件&#xff1f;所有的Landsat8 1级数据产品中均包含MTL.txt(Metadata File)文件。Landsat MTL文件包含对数据的系统搜索和归档分类有益的信息。该文件还包含关于数据处理和恶对增强陆地卫星数据有重要价值的信息&#xff08;例如转换为反射率和辐射亮度&am…...

好的提高代码质量的方法有哪些?有什么经验和技巧?

用于确保代码质量的6个高层策略&#xff1a; 1 编写易于理解的代码 考虑如下这段文本。我们有意地使其变得难以理解&#xff0c;因此&#xff0c;不要浪费太多时间去解读。粗略地读一遍&#xff0c;尽可能吸收其中的内容。 〓ts〓取一个碗&#xff0c;我们现在称之为A。取一…...

yum保留安装包

一. 用downloadonly下载 1.1 处理依赖关系自动下载到/tmp/pages目录&#xff0c;pages这个目录会自动创建 yum install --downloadonly --downloaddir/tmp/pages ceph-deploy注意&#xff0c;如果下载的包包含了任何没有满足的依赖关系&#xff0c;yum将会把所有的依赖关系包下…...

ERP系统哪家比较好?

ERP系统哪家好&#xff1f;在选择ERP系统时&#xff0c;我们可以按照这三个维度&#xff0c;然后再按照需求去选择ERP系统。 市面上ERP软件大概可以分为三大类&#xff1a; ① 标准ERP应用&#xff1a;功能比较固定&#xff0c;难以满足个性化需求&#xff0c;二次开发难度很高…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...

flow_controllers

关键点&#xff1a; 流控制器类型&#xff1a; 同步&#xff08;Sync&#xff09;&#xff1a;发布操作会阻塞&#xff0c;直到数据被确认发送。异步&#xff08;Async&#xff09;&#xff1a;发布操作非阻塞&#xff0c;数据发送由后台线程处理。纯同步&#xff08;PureSync…...

向量几何的二元性:叉乘模长与内积投影的深层联系

在数学与物理的空间世界中&#xff0c;向量运算构成了理解几何结构的基石。叉乘&#xff08;外积&#xff09;与点积&#xff08;内积&#xff09;作为向量代数的两大支柱&#xff0c;表面上呈现出截然不同的几何意义与代数形式&#xff0c;却在深层次上揭示了向量间相互作用的…...