APK 瘦身

2024-01-04

APK 瘦身的主要原因是考虑应用的下载转化率和留存率,应用太大了,用户可能就不下载了。再者,因为手机空间问题,用户有可能会卸载一些占用空间比较大的应用,所以,应用的大小也会影响留存率。

1 APK 的结构

包含以下目录:

  • assets/:包含了应用的资源,这些资源能够通过 AssetManager 对象获得;
  • lib/:包含了针对处理器层面的被编译的代码。这个目录针对每个平台类型都有一个子目录,比如 armeabi,armeabi-v7a,arm64-v8a,x86,x86_64 和 mips;
  • res/:包含了没被编译到 resources.arsc 的资源;
  • META-INF/:包含 CERT.SF 和 CERT.RSA 签名文件,也包含了 MANIFEST.MF 文件;

包含以下文件:

  • classes.dex:包含了能被 Dalvik/Art 虚拟机理解的 .dex 文件格式的类;
  • resources.arsc:包含了被编译的资源。该文件包含了 res/values 目录的所有配置的 xml 内容。打包工具将 xml 内容编译成二机制形式并压缩。这些内容包含了语言字符串和 styles,还包含了那些内容虽然不直接存储在 resources.arsc 文件中,但是给定了该内容的路径,比如布局文件和图片,所以又叫资源映射表;
  • AndroidManifest.xml:包含了主要的 Android 配置文件。这个文件列出了应用名称、版本、访问权限、引用的库文件。该文件使用二进制的 .xml 格式存储;

主要是针对 lib/ 、res/ 和 classes.dex 进行瘦身:

APK 文件

2 图片优化

2.1 一套图片资源

图片优化主要是针对多套图片资源的问题。

Android 常见分辨率

  • ldpi:320 x 240
  • mdpi:480 x 320
  • hdpi: 800 x 480
  • xhdpi:1280 x 720
  • xxhdpi:1920 x 1080

因为 APP 在加载图片时会优先加载对应分辨率文件夹下的图片,如果在对应的分辨率文件夹下没有所要的图片,就会找高分辨率文件夹下的图片。那么,如果我们把所有的图片都放在高分辨率的文件夹下是不是就可以了呢?并不是,这样做会导致低分辨率手机加载图片时会消耗更多的内存。

2017年后,Android 手机一般大小在 5 寸以上,分辨率至少是 720p,1080p,所以对应的 dpi(Dots Per Inch 每英寸点) 分别为:

  • 1280 x 720,5 寸的手机,对应的 dpi 大约是 300dpi;
  • 1080 x 1920,5 寸的手机,对应的 dpi 大约是 440dpi;

对于绝大多数 APP 来说,只需要取一套设计图就足够了。鉴于现在分辨率的趋势,建议取 720p 的资源,放在 xhdpi 目录。相对于多套资源,只使用 720P 的一套资源,在视觉上差别不大,很多大公司的产品也是如此,但却能显著的减少资源占用大小,身边也能减轻设计师的出图工作量了。

注意,这里不是说把不是 xhdpi 的目录都删除,而是强调保留一套设计资源就够了。

2.2 使用 TinyPNG 有损压缩

TinyPNG 工具只支持上传 PNG 图片到官网上压缩,然后下载保存,在保持 alpha 通道的情况下对 PNG 的压缩可以达到 1/3 之内,而且用肉眼基本上分辨不出压缩的损失。

TinyPNG 的官方网站:http://tinypng.com/

2.3 使用 jpg 格式

如果对于非透明的大图,jpg 将会比 png 的大小有显著的优势,虽然不是绝对的,但是通常会减小一般都不止。

在启动页,活动页等之类的大图展示区采用 jpg 将是非常明智的选择。

2.4 使用 webp 格式

webp 支持透明度,压缩比 jpg 更高且显示效果却不输 jpg,官方评测 quality 参数等于 75 均衡最佳。

相对于 jpg、png,webp 作为一种新的图片格式,限于 android 的支持情况暂时还没用在手机端广泛引用起来。从 Android 4.0 开始原生支持,但不支持包含透明度,直到 Android 4.2.1+ 才支持显示含透明度的 webp,使用的时候要特别注意。

官方介绍:https://developers.google.com/speed/webp/docs/precompiled

2.5 缩小大图

如果经过上述步骤之后,你的工程里面还有一些大图,考虑是否有必要维持这样的大尺寸,是否能适当的缩小。事实上,由于设计师出图的原因,我们拿到的很多图片完全可以适当的缩小而对视觉影响是极小的。

2.6 覆盖第三库里的大图

有些第三方库里引用了一些大图但是实际上并不会被我们用到,就可以考虑用 1x1 的透明图片覆盖。这样会导致 drawable 文件下包含了一些莫名其妙的名称的 1x1 图片…

2.7 SVG

对于位图图像来说,其的大小是固定的,分辨率低,占的内存空间小,分辨率高,占的内存空间大。

SVG,SVG 意为可缩放矢量图形(Scalable Vectors Graphics),使用 XML 格式定义图像,适用简单的小图标。

首先在 res 包目录下点击 New —> Vector Asset:

添加 svg 图片

进入 Configure Vector Asset 窗口:

添加 svg 类型的图片

选择 Local file (SVG, PSD),选择要导入的 svg 图片:

添加 svg 类型的图片

点击 Next —> Finish:

添加 svg 类型的图片

导入成功:

svg 导入成功

使用:

使用 svg

在 apk 包的 drawable 目录下是 .xml 文件而不是 .png:

svg 图片所在位置

使用 svg 可以不用考虑图片的分辨率、大小、颜色等信息。.xml 的性能比 .png 更好,占用内存更少,转换成机器码的效率更高。

如果 SVG 文件包含不受支持的功能,将在 Vector Asset Studio 的底部显示一个错误提示。不支持的功能:

  • 滤镜效果:不支持投影,模糊和颜色矩阵等效果;
  • 文本:建议使用其他工具将文本转换为形状;

svg 文件出错

Tint 着色器:可以直接在 xml 文件中修改矢量图的颜色,但是并不建议直接修改,我们一般用 Tint 着色器去修改矢量图的颜色:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#00ff00" android:state_pressed="true" />
    <item android:color="@android:color/black" />
</selector>

<ImageView
    android:id="@+id/iv"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:clickable="true"
    android:focusable="true"
    android:src="@drawable/fanhui"
    app:tint="@color/selector_back_color" />

使用 .svg 格式的图片,转换成 vector 格式的文件,不同大小,不同颜色的图片只需要一个文件就可以了实现了。

矢量图是由点与线组成,和位图不一样,它再放大也能保持清晰度,而且使用矢量图比位图设计方案能节约 30~40% 的空间,现在谷歌一直在强调扁平化方式,矢量图可很好的契合该设计理念。

优势

  • 占用内存空间小
  • 无限拉伸不会出现锯齿,可以照顾不同尺寸的机型;
  • Android Studio 自带很多资源,减小 UI 的工作量;

劣势

  • 只支持 5.0 及以上的系统;
  • 与位图相比多了一层计算,需消耗更多的性能;
  • 不支持 .9 图;
  • 不适合表现真实照片和复杂图形,一般使用在简单的 icon 和动画上;

3 动态库打包配置

在 Android 开发中,so 库是不可或缺的。so 库指的是动态链接库,也就是在运行时载入内存的库文件。在 Android 应用程序中使用 so 库可以大大降低内存的使用,提高系统的性能。so 库文件的产生主要有两种方式:

  • 使用 C/C++ 编写的 Native 代码,将 Native 的 C/C++ 代码编译为 so 文件,通过 Java Native Interface(JNI) 的方式使用 so 文件;
  • 使用第三方的 so 库文件,例如 FFmpeg、OpenCV 等开源库;

so 库是由 ndk 编译出来的动态库,是 C/C++ 写的,所以不是跨平台的,即每一个平台需要使用对应的 so 库。

ABI 是应用程序二进制接口简称(Application Binary Interface),定义了二进制文件(尤其是 .so 文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。

在 Android 系统上,每一个 CPU 架构对应一个 ABI:arm64-v8a,armeabi-v7a,armeabi,x86_64,x86,mips64,mips。现在我们一般只需要配置 arm64-v8a。

  • arm64-v8a:第 8 代 64 位 ARM 处理器。目前,国内的应用生态正在向 64 位架构过渡,移动芯片平台也将逐步弱化对 32 位应用的支持(兼容 armeabi-v7a、armeabi);
  • armeabi-v7a:第 7 代及以上的 AMR 处理器(兼容 armeabi);
  • armeabi:第 5、6 代的 ARM 处理起,早期的手机用的比较多;
  • x86_64:64 位的平板;
  • X86:平板、模拟器用的比较多;
  • mips64/mips:极少用于手机可以忽略;

在 build.gradle 构建脚本中,配置 ndk 编译的动态库 CPU 架构类型:

android {
    defaultConfig {
        ndk {
        		abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }
    }
}

按照以上配置,打包时会将 4 种 CPU 架构的动态库都配置到 APK 中。事实上,绝大多数的应用都不需要配置全架构的动态库,arm64-v8a 架构的 CPU 可以向下兼容:

android {
    defaultConfig {
        ndk {
        		abiFilters "arm64-v8a"
        }
    }
}

4 移除无用资源

Android Studio 给我们提供了一键移除所有无用的资源,如下所示:

移除无用资源

移除无用资源

但是这种方式不建议使用,因为如果某资源仅存在动态获取资源 id 的方式,那么这个资源会被认为没有使用过,从而会直接被删除。

动态获取的方式:getResources().getIdentifier(“name”, “defType”, getPackageName())

另外一种方式是通过 Analyze Code 手动移除无用资源:

Analyze Code

Run Inspection by Name

搜索 unused resources:

unused resources

选择搜索范围:

选择搜索范围

无用资源:

无用文件

5 代码压缩-混淆

  • 长类名改为短类名;
  • 长方法名改为短方法名;
  • 变量名改变;
  • 删除无用代码;
  • 缺点:启用后编译较慢,混淆可能导致编译出错或其他 bug。debug 模式下最好不要做混淆,因为做了混淆之后方法名、类名都会发生变化,不容易定位 bug。
buildTypes {
  
  	debug {
        minifyEnabled false // 不做混淆
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  
    release {
        minifyEnabled true // 做混淆
          shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

minifyEnabled 用来开启删除无用代码,比如没有引用到的代码。

shrinkResources 用来开启删除无用资源,也就是没有被引用的文件(drawable、layout),实际上并没有删除,只是保留文件名,但是没有内容。但是需要知道资源是否被引用,需要配合 minifyEnabled 来使用,只有当两者都为 true 的时候才能真正的删除无效代码和无用资源。

资源压缩只与代码压缩协同工作。

默认情况未启用严格模式(严格模式是指清除掉资源本身,非严格模式指的是只清除资源内容),如需启动则设置 shrinkMode,创建 keep.xml,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/tools"
           tools:shrinkMode="strict" >

如果开发者想要特定保留或者必须移除的资源,可以进行自定义配置:

  • tools:keep:指定要保留的资源,如果有多个资源保留需要用逗号隔开;
  • Tools:discard:指定要移除的资源,如果有多个资源移除需要用逗号隔开;
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:discard="@color/selector"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:shrinkMode="strict">
		
  	<!-- 该设置支持 * 通配符设置 -->
    <!-- shrinkMode="strict": 该模式只保留在代码或者资源文件中明确引用的资源-->
    <!-- shrinkMode="safe": 该模式会保留所有明确引用的资源以及可能被 Resources.getIdentifier() 动态引用的资源-->

</resources>

6 动态加载 so 库

Java 加载 so 库的方式有两种:

  • 静态加载:System.loadLibrary(String libname),参数为 so 库名称,位于 APK 的 lib 的目录下。采用此种方式是要将 so 库打包进 apk 或者 jar 包中的;
  • 动态加载:System.load(String filePath),参数为 so 库在磁盘中的完整路径,可以加载磁盘中的 so 库文件;
//加载的是 jni_mix.so,注意的是这边只需要传入 "jni_mix"
static {
  	System.loadLibrary("jni_mix");
}
//传入的是 so 文件完整的绝对路径
System.load("/data/data/[packagename]/lib/jni_mix.so")

静态加载会导致 apk 包比较大,所以采用动态加载 so 库的形式,也就是从网络上下载,放入本地数据目录下。这样做的好处是不仅减小了 apk 的大小,而且可以随时使用最新的依赖库,这也是动态加载的最多的用途之一。

用动态加载技术,编译前不把 so 文件放入 jniLibs 目录(原因很多,比如想减少安装包的大小),自然打包生成的安装包也不包含该 so 库。接着在手机上安装这个 apk 并启动 APP,如果 APP 的运行不涉及到 jni 方法的调用,那就当 so 不存在;如果 APP 打开某个页面,而该页面又需要调用 jni 方法,则 APP 自动到指定地址下载需要的 so 文件,然后保存到用户目录,并从用户目录加载该 so,最后再调用 jni 方法。

步骤一:下载 so;

步骤二:拷贝 so 至私有(data)目录;

步骤三:通过绝对路径加载 so;

7 插件化压缩包

通过插桩式来实现加载插件,AssetManager 加载资源和 java 文件

插件化开发就是将整个 APP 拆分成很多模块,每个模块都是一个 APK,最终打包的时候将宿主 APK 和插件 APK 分开打包,插件 APK 通过动态下发到宿主 APK。

插件可以放到服务器加载。

8 删除无用的语言资源

在 resources.arsc 文件下可以查看支持的语言:

语言资源

大部分应用其实并不需要支持几十种语言的国际化支持。比如只支持中文、英文:

android {
		defaultConfig {
				resConfigs "zh", "en" // 支持中文、英文
		}
}

去除无用资源之后:

去除无用资源之后

9 shape 背景、着色、在线化素材、避免重复库

9.1 使用 shape 背景

特别是在扁平化盛行的当下,很多纯色的渐变的圆角的图片都可以使用 shape 实现,代码灵活可控,省去了大量的背景图片。

9.2 使用着色方案

相信你的功能里面也有很多 selector 文件,也有很多相似的图片只是颜色不同,通过着色方案我们能大大减轻这样的工作量,减少这样的文件。

借助 android support 库乐意实现一个全版本兼容的着色方案,参考代码 DrawableLess.java

9.3 在线化素材库

如果你的 APP 支持素材库(比如聊天表情库)的话,考虑在线加载模式,因为往往素材库都有不小的体积。

这一步需要开发者实现在线加载,一方面增加代码的复杂度,一方面提高了 APP 的流量消耗,建议酌情选择。

避免重复库

避免重复库看上去是理所当然的,但是秘密总是藏得很深,一定要当心你引用的第三方库又引用了哪个第三方库,这就很容易出现重复的库了,比如使用了两个图片加载库:Glide 和 Picasso。

通过查看 exploded-aar 目录和 External Libraries 或者反编译生成的 APK,尽量避免重复的库的大小,减小 APP 大小。

10 清除冗余代码

版本迭代过程中,因为删减功能经常有冗余代码和第三方库留下,这或多或少都会增加包体,这种情况下没有捷径,只能每个文件查找,这是苦力活。还有要查看第三方库有没有可能精简,比如谷歌分基础、广告和分析包,网络库、supportv4 等,这个就具体情况具体分析了,不多阐述。

11 使用微信资源压缩打包工具

微信资源压缩打包工具通过短资源名称,采用 7zip 对 APP 进行极致压缩实现减小 APP 的目标,效果非常好,强烈推荐。

建议开启 7zip,注意白名单的配置,否则会导致有些资源找不到,官方已经发布 AndResGuard 到 gradle 中了,非常方便。

12 Provided 编译

对于一些库是按照需要动态加载的,可能在某些版本并不需要,但是代码又不方便去除否则编译不过。

对于 provided 可以保证代码编译通过,但是实际打包中并不引用第三方库,实现了控制 APP 大小的目标。

但是也同时就需要开发者自己判断不引用这个第三方库时就不要执行到相关的代码,避免 APP 崩溃。

参考

【Android】浅谈APP的瘦身之路
Android SO库的详细阐述
安卓APK安装包arm64-v8a、armeabi-v7a、x86、x86_64有何区别?如何选择?
【转】android中的armeabi、armeabi-v7a、arm64-v8a及x86等
【Android 安装包优化】动态库打包配置 ( “armeabi-v7a“, “arm64-v8a“, “x86“, “x86_64“ APK 打包 CPU 指令集配置 | NDK 完整配置参考 )

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

APK 瘦身 的相关文章

  • 无法解析符号“AndroidJUnit4”

    显然我需要正确的导入语句来解决这个问题 根据文档用于AndroidJUnit4 http developer android com reference android support test runner AndroidJUnit4 h
  • Android:是否有一种简单的方法可以为视图创建圆角,而不必每次都创建单独的可绘制对象?

    我在互联网上浏览了各种解决方案 这些解决方案使我们能够创建带有圆角的视图 其中大多数需要使用创建自定义视图 或者每次我们需要圆角视图时都需要在 xml 或九个补丁中创建可绘制对象 问题是 当我实现此类视图时 我需要为每个此类视图创建一个可绘
  • 按大小、日期、名称等在回收器视图中排序并记住选择

    我正在制作图库应用程序 我想为其添加排序功能 我可以使用以下命令在运行时对项目进行排序Comparator但问题是 每当我退出应用程序时 列表都会再次从数据库中出来 并且所有列表都未排序 我想在我的应用程序中提供按日期 大小 名称等排序的选
  • Android NumberPicker 带字符串

    I have customised the NumberPicker to show text The output is this 当我按 确定 时 我想将 e x 鼠标添加到我的列表 文章 中 我得到的是索引值 int 它由 array
  • Android:从 https url 获取响应

    问候 我正在开发一个 Android 应用程序 需要通过 https 打开一个 url 带有 POST 参数 并获取响应 我有一个自签名证书 这让情况更加复杂 我还需要接受cookies 有人知道从哪里开始吗 提前谢谢了 Android 附
  • 如何创建 Google Play 音乐的直接链接?

    据我所知 应用程序的直接链接是 gt market apps collection
  • 方法不必要地被调用?

    我有一个 BaseActivity 它可以通过其他所有活动进行扩展 问题是 每当用户离开 暂停 活动时 我都会将音乐静音 我也不再接听电话 问题是 onPause每当用户在活动之间切换时就会被调用 这意味着应用程序不必要地静音和停止tele
  • Android BLE - 如何分块读取大特征值(使用偏移量)?

    我正在使用 Android SDKandroid 蓝牙 and android 蓝牙 le APIs 我想实现一个应用程序 发挥核心作用 并连接到 BLE 外设以读取特征值和描述符 应用程序需要读取的特征值较大 因此需要分块连续读取 我对如
  • 如何在phonegap上使用GCM处理android中的多个推送通知

    当推送通知到达时 如果用户无法查看该通知 他收到另一条通知 之前的通知正在更新为新的 但它不应该更新为最新的 我们需要单独显示每个通知 这可以使用 GCM 吗 我已经使用Phonegap来开发应用程序 PushPlugin 支持在有效负载中
  • 拦截来自外部应用程序的意图

    假设我想开发一个以某种方式扩展的应用程序 让我说 合作 非常受欢迎的应用程序我显然无法控制 为了简单起见 我们还假设非常著名的应用程序作者不会发布更新来阻止我的应用程序 我研究了该应用程序的功能并发现它广泛使用BroadcastReceiv
  • AWS MobileHub:重命名 Android / iOS 示例项目

    我是 AWS Mobilehub 的新手 我喜欢它允许我使用 AWS 配置选项创建项目 但是 当我尝试构建应用程序 ios swift android 时 它总是使用我的示例项目作为项目名称 在 AWS 项目的大多数配置设置中 例如使用 c
  • 如何消除警告:使用“$”而不是“.”对于 Eclipse 中的内部类

    我是 Android 开发新手 当我将 eclipse 和 Android SDK 更新到最新版本后 我收到警告 Use instead of for inner classes or use only lowercase letters
  • android:widgetLayout 和 android:layout 之间的区别?

    我得到一些奇怪的配置 其中 widgetLayout 配置列表项的内部空间 而布局配置整个项目列表和屏幕背景 有人能真正解释一下什么是 widgetLayout 吗 android layout 整个首选项的布局 包括标题 摘要和小部件 a
  • 如何在将数据发送到 Firebase 数据库之前对其进行加密?

    我正在使用 Firebase 实时数据库制作聊天应用程序 我知道 Firebase 非常安全 只要您的规则正确 但我自己可以阅读使用我的应用程序的人的所有聊天记录 我想阻止这种情况 为此我需要一种解密和加密方法 我尝试使用凯撒解密 但失败了
  • 在 PHP 中设置通知的 FCM 通道 ID

    我正在尝试使用 PHP 向 Android 设备发送 FCM 通知 我的代码适用于 Android O 之前的设备 在Android O中 我们还需要在请求中设置通道ID来接收通知 我不知道该怎么做 我已在应用程序中完成了必要的设置 并使用
  • 使用 IntelliJ / Android Studio 调试基于 gradle 的单元测试

    我正在使用robolectric gradle 插件 https github com robolectric robolectric gradle plugin为 Android 编写单元测试 到目前为止 除了能够使用 Android S
  • 为什么在回收器视图中滚动后值会消失?

    Data before scrolling Data after scrolling 我的应用程序的问题如上图所示 输入数据后 如果我在将项目添加为可滚动后滚动 数据就会消失 作为进一步的解释 有时输入的数据出现在已添加的其他项目中 为了解
  • Android - 如何合并两个视频

    基本上 我正在寻找一种将两个 mp4 视频文件 在 SD 卡上 组合在一起的方法 更像是在第一个视频的末尾附加第二个视频 我进行了很多搜索 但找不到合适的解决方案 好吧 我根本找不到任何解决方案 所以我的问题是 是否有一个库可以组合 并可能
  • 防止 Firebase 中的待处理写入事务不起作用

    我的目标是在单击按钮时将名称插入 Cloud Firestore 中 但如果用户未连接到互联网 我不希望保存处于挂起状态 我不喜欢 Firebase 保存待处理写入的行为 即使互联网连接已恢复 我研究发现Firebase 开发人员建议使用事
  • 如何自动更新Android Studio?

    我需要将 Android Studio 更新到 0 9 9 版本 但是当我按 下载 在更新信息对话框上 时 它会将我发送到此处 http developer android com sdk index html http developer

随机推荐

  • 在centos7部署redis7

    一 目标 在centos7 9上部署安装redis 7 2 3 二 步骤 官网 https redis io download 1 下载合适版本的redis wget https github com redis redis archive
  • 【Python】Python中逗号转为空格的方法

    Python中将逗号转换为空格的几种方法 以及将其应用在实际开发中的示例 Python是一种功能强大的编程语言 其提供了很多内置函数 方便我们快速 高效地处理数据 一 使用replace函数 Python中的字符串函数replace可以用来
  • vue项目日期处理day.js

    dayjs安装 1 npm 安装 npm install dayjs save 2 项目使用 import dayjs from dayjs ES 2015 dayjs format 使用介绍 1 秒 获取或设置秒 接受0到59的数字 如果
  • Mybatis Plus 基础功能 BaseMapper和基础配置以及注解

    文章目录 Mybatis Plus 导入依赖 定义Mapper 约定 常见配置 Mybatis Plus 导入依赖 官网看一下也行 plus官网 spring boot3 版本
  • Python机器学习实战:用Python构建10个有趣的应用

    机器学习是一门强大的工具 可以用于解决各种各样的问题 通过学习机器学习 您可以开发出能够自动化任务 做出预测甚至创造艺术的应用程序 如果您是一名 Python 开发人员 那么您将很高兴知道 有许多可以用 Python 构建的有趣机器学习应用
  • 江河湖泊生态水文监测物联网解决方案

    方案背景 江湖湖泊具有重要的经济效益和生态效益 是重要的资源储备 近年来 各级积极采取措施 加强江河湖泊治理 管理和保护 在防洪 供水 发电 航运 养殖等方面的综合发展 随着纳入管理的江河湖泊等水体越来越多 范围越来越广 很多水污染 非法采
  • Laya游戏开发中AI寻路解决方案

    1 AI自动寻路 机器人代码重构 按照目标点去执行逻辑 提前几帧判断直线 非直线的情况下 预设转弯角度 角度判断到达直线后开始执行到目标点的逻辑 2 U3D布点寻路 3 NevMesh Js寻路插件 NevMesh Js你可以在Laya引擎
  • Python生成器:优雅而高效的迭代器

    本文将为大家介绍下 Python 中的 生成器 它有何强大之处 实际开发任务中 for循环与生成器我们将如何取舍 Python是一种强大而灵活的编程语言 拥有丰富的标准库和特性功能 其中之一就是 生成器 生成器 是Python中一种非常实用
  • TXT文本删除第一行文本变成空要如何解决呢

    首先大家一起来看下这个TXT文本里面有多行内容 想把开头第一行批量删除不要掉 1 如果是一两个本可以手动删除也很方便哦 如果文本量比较大如几十几 几百个文本大家一直都选用 首助编辑高手 工具去批量操作哦 批量操作可以大大提高工作效率 接来看
  • 办公自动化-邮件通知和微信通知

    在工作中 或者学习中或者生活上等 需要定时提醒自己或其他人 处理一些待办任务事项 需要发邮件通知下 同时可能会要求发送文件之类的事情 由于现在大家微信使用频率最高 所以能发送微信通知消息 效果更好 同时开通下微信通知功能 第一步 邮件通知工
  • Java 跨平台实现

    Java 跨平台实现 1 Java虚拟机 JVM 2 中间代码 字节码 3 Write Once Run Anywhere WORA 4 Java 标准库 5 安全性与隔离 6 Java Community Process JCP
  • 朋渤WMS助力电商:无代码API连接广告与CRM系统

    优化用户运营的无代码解决方案 如今 企业追求高效的用户运营变得尤为重要 而这一切的基础是系统间的无缝集成 朋渤WMS提供了一个无需编写API代码的集成方案 通过其无代码开发平台 不仅优化了工业电气行业的业务流程 还让电商企业在激烈的市场竞争
  • GHM-XGBOOST模型的学习和理解

    Gradient Harmonized Margins GHM GHM 是一种损失函数 主要用于解决类别不平衡问题 GHM 损失函数能够关注较难的样本 对于容易的样本降低权重 从而在训练过程中更好地平衡了损失 这有助于提高模型对于少数类别的
  • SQL查询 字符串数据

    查询房屋特色 例如 1 2 3 多个 字符串 tag ids this gt request gt param tag ids s if tag ids arr explode tag ids tag ids map arr foreach
  • web前端学习怎么能快速入门

    Web前端开发是一个热门的职业领域 很多人都希望能够快速入门并掌握相关技能 下面将从制定学习计划 项目实战案例练习 以用为学 与培训班老师多交流 自主学习能力的培训等5个方面详细介绍如何在web前端培训班学习 1 制定web前端学习计划 在
  • 在Java培训班怎么学习?这5个学习技巧送给你

    在Java培训班学习Java编程语言是一个很好的学习平台 但是如何更有效地学习呢 下面我将为大家介绍5个学习技巧 希望能帮助到大家 Java是一种面向对象的编程语言 被广泛应用于企业级应用开发 移动应用开发 大数据处理等领域 学习Java编
  • 培训学习大数据知识有哪些方法

    学习大数据知识是当前非常热门的话题 随着大数据技术的不断发展 越来越多的人开始关注并学习大数据知识 在大数据培训班学习大数据知识是一个非常好的选择 下面我将从制定大数据学习计划 项目实战案例练习 以用为学 与培训班老师多交流等四个方面来详细
  • 旧硬盘插电脑上显示要初始化怎么办?了解原因和解决方案

    在使用旧的硬盘插入电脑时 有时会遇到需要进行初始化的情况 这种情况可能是由于多种原因引起的 而初始化硬盘将会导致所有数据丢失 给用户造成不便和损失 因此 本文将介绍解决旧硬盘需要初始化的问题的方法 并提供一些建议来帮助读者避免数据丢失 一
  • Linux配置Acado

    如果需要使用acado的matlab接口 请移步 Linux Matlab配置Acado 首先 安装必要的软件包 sudo apt get install gcc g cmake git gnuplot doxygen graphviz 在
  • APK 瘦身

    APK 瘦身的主要原因是考虑应用的下载转化率和留存率 应用太大了 用户可能就不下载了 再者 因为手机空间问题 用户有可能会卸载一些占用空间比较大的应用 所以 应用的大小也会影响留存率 1 APK 的结构 包含以下目录 assets 包含了应