Android有效地减少方法数
来源:互联网 发布:淘宝网夏秋棉麻连衣裙 编辑:程序博客网 时间:2024/06/03 13:09
原文链接http://jeroenmols.com/blog/2016/05/06/methodcount/
由于绿地项目是个罕见的工程,你有机会继承了一个陈旧代码库。如果你跟我一样幸运,代码库已经有超过65k个方法,导致构建时间令人烦躁的长。
今天,我会展示如何可视化你当前的方法数,并掌握哪些库占据了最大部分。接着就是减少方法数,并一劳永逸的移除讨厌的multidex解决方案。
可视化方法数
可视化方法数的最简单和最吸引人的方式(恕我直言)是使用方法Dexcount Gradle Plugin。应用到项目是很容易,只要在根build.gradle中添加classpath依赖,并在App的build.gradle中应用这个插件。
// root build.gradle filebuildscript { repositories { jcenter() // or mavenCentral() } dependencies { classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.0' }}
// app build.gradle file (apply AFTER Android plugin)apply plugin: 'com.getkeepsafe.dexcount'
执行一个正常的工程构建 ./gradlew assembleDebug
就在终端中打印出当前的方法数。
并在输出文件夹中生成一个交互图像报告build/outputs/dexcount/debugChart
:
点击上图来看看效果
使用图形化表示应用中左右包的方法数,很方便就可以找出那个库正在消耗宝贵的方法数。一些常见的嫌犯是单独的大型库,如Guava和未拆分的Google play服务。在下节将看到我们能对这些库做什么。
减少方法数
选择合适的库
通常我推荐从不优化,除非你遇到了问题。但对于方法数,我真的建议在开始使用库前考虑方法数,有2个原因:
- 替换应用中存在的库是非常具有挑战性,几乎不能的。
- 很多开发者使用巨大的库而只实现简单的事情。(
Strings.isNullorEmpty()
还有谁?)注意,你不需要使用一个库干所有的事情!
幸运的是,这有一个非常棒的网址methodscount.com可在开始使用库之前告诉你方法数。这可以真正的帮助你的应用避免使用”大库”却仅带来有限的收益。
替换已存在的库
通常有多个库完成相同的功能。以图片加载为例:
每个库都有各自的优势和功能,所以明智的选择和平衡需要的功能与方法数带来的影响。
话虽这么说,替换现有库是令人难以置信的困难,并且短期内不可行。后面,我将建议一种折中方案来减少现有库的方法数。
执行Proguard
Proguard是个伟大的工具,可以从应用中剔除无用的代码,但通常只在发布构建时执行它来节省宝贵的构建时间。如果对你不是问题,你也可以在调试版本中启动Proguard:
buildTypes { debug { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' }}
减少库大小
如果替换现有库或者执行Proguard都不可行,那么事情就变得很有趣了。因为如果Proguard可以在发布版本时剔除代码,为什么不在使用它之前创建一个带更少方法的修改版的库呢?
嗯,这使可能的,但你不行手动指定你要使用库的哪部分!这是因为Proguard在库剔除过程中不知道应用需要那些方法的上下文。
让我们以我最近开始工作的工程为例。Guava在整个工程中广泛使用,使得清除它很困难/有风险。但由于庞大的方法数,我们不断的与65k方法数限制勾搭,并不得不启用multidex。
首先你需要知道应用真正使用了库的哪部分。可在src
目录执行下面的命令,就可以得到了。
rep -roh . -e 'com.google.common.*' | sort | uniq
该命令会检索所有包含库前缀引入语句(对于Guava,前缀是com.google.common
),从grep输出中删除所有干扰,排序并挑出所有唯一的引用。
接着,我创建一个简单的Proguard配置,该配置保存所有顶级包名,不适用任何混淆或优化。
-dontoptimize-dontobfuscate-keep public class com.google.common.base.** { public *;}-keep public class com.google.common.collect.** { public *;}-keep public class com.google.common.primitives.** { public *;}-keep public class com.google.common.util.** { public *;}
现在我们适用一个小Gradle脚本,该脚本拿库作为输入,对库执行Proguard,并生成一个新库。如果你感兴趣,我建议你看看源码,它是基于@mr_ligi写的脚本。这个Gradle脚本输出一个压缩版本的库,可将库拷贝到工程的libs文件夹。
看一下我们的例子,这个过程节省了4000个方法,我们距dex方法数限制只差一点了。
回到画板,因为这使远远不够的!结果发现collect
包有超过8000个方法,因此我决定只保持这个类而不是整个包。
当试图在应用中使用库时,更积极的方法很有可能导致编译错误,所有我不得不遍历并添加额外的类,直到解决了所有的错误。由此产生的Proguard配置如下:
-dontoptimize-dontobfuscate-keep public class com.google.common.base.** { public *;}-keep public class com.google.common.collect.Sets-keepclassmembers class com.google.common.collect.Sets** { *; } -keep public class com.google.common.collect.Collections2 -keepclassmembers class com.google.common.collect.Collections2** { *; }-keep public final class com.google.common.collect.Lists-keepclassmembers class com.google.common.collect.Lists** { *; }-keep public final class com.google.common.collect.Iterables-keepclassmembers class com.google.common.collect.Iterables** { *; }-keep public class com.google.common.collect.ImmutableList.** { public *;}-keep public class com.google.common.io.CharStreams { public *;}-keep public class com.google.common.collect.HashMultiset-keepclassmembers class com.google.common.collect.HashMultiset** { *; }-keep public class com.google.common.collect.HashBiMap-keepclassmembers class com.google.common.collect.HashBiMap** { *; }-keep public class javax.annotation.Nullable.** { public *; }-keep public class com.google.common.util.** { public *;}-keep public class com.google.common.primitives.** { public *;}
结果接近减少了4500个方法,总计删除了8500个方法!
进一步来说,我们的构建时间,不仅减少了,因为不需要multidexing了,也是因为编译器现在处理的代码更少了。
显然,你的里程取决于你选择什么库。对于低耦合,高聚合的库(例如Guava),这种技术工作的相当好,但对其他库可能就没啥效果。
免责声明
上面展示的技术要慎用!由于不依赖Proguard剔除那些不需要,我们现在要纯手工操作,这很容易出错.
总结
击中65k方法数限制是真实的痛苦,但明智的选择使用哪个库可以让你走得更远。幸运的是像Dexcount Gradle Plugin和methodscount.com这样伟大的工具可以帮你做出这些决定。
对于已有工程,总试图用替代品的更换现有多方法的库。如果这是不可行的,并且你觉着使用Proguard很舒适,可以使用后者预处理和收缩现有库。
本文整合的一个基本例子可在GitHub中获取到。
你可在twitter上@molsjeroen找到我,或给我柳岩!
- Android有效地减少方法数
- 产品使用Dagger 2——减少方法数
- 程序员如何有效地做到纵向管理,减少压力
- Android Developers:有效地显示位图
- 减少Http请求数
- 减少XML文件数
- 减少oracle进程数,减少OS信号量
- Android方法数
- android方法数统计
- Android方法数统计
- 如何有效地解Bug (RED方法)
- 如何有效地解Bug (RED方法)
- 如何有效地解Bug (RED方法)
- 网站减少Http连接数
- 怎样减少http请求数
- 减少配置的方法
- Linux减少time_wait方法
- Linux减少time_wait方法
- LeetCode-168.Excel Sheet Column Title
- 怎样在Eclipse中快速查看各种源代码?
- 鼠标双击
- 基数排序
- 月薪3万的程序员告诉你:这样工作才能拿高薪
- Android有效地减少方法数
- 四大组件之Service(二)-Service在各种情况下的生命周期
- 堆排序
- Android LayoutInflater详解
- 桶排序
- 第十.十一周项目3 - 警察和厨师——2
- Unity3D内部串口通信和Unity3D与Winform程序的串口通信的实现和异常问题
- 怎样在Eclipse中快速查阅各种api/docs文档?|
- AOPR软件怎么更改Excel VBA密码