如何正确处理 class 依赖关系以在 Java/Android 和 Gradle 中利用增量编译?
How to properly deal with class dependencies to utilize incremental compilation in Java/Android with Gradle?
我改进了构建系统并激活了增量构建和编译,如 this question. To my disappointment, incremental compilation didn't improve build times as much as I expected from reading Gradles blog post 中所述。
经过一些调查,我意识到问题在于,即使我只在应用程序深处的一个小 class 地方添加评论,显然几乎整个代码库都被重建了。事实上,我触摸哪个 class 并不重要,Gradles --debug
输出显示它基本上总是重新编译 476 classes.
Incremental compilation of 476 classes completed in 12.51 secs.
虽然我知道更改文件中的 public static
常量会触发完全重新编译(只是稍微慢一点),但我不明白如何正确分解 class 依赖关系以便增量编译确实有效。确定影响增量编译的 class 依赖项的确切规则是什么?我可以阅读一些示例 here,但它似乎根本不适用于我们的(相当标准的)项目。
我自己的一些测试产生了以下结果:
// One of my main classes that has lots of class dependencies
public class A{
public void foo() {
// This line produces a dependency between A and B. So changing just
// a comment in B triggers recompilation of all classes attached to A
B b1 = new B();
}
}
// A small helper class that I want to change
public class B {
public void bar() {
// This line does not create a dependency, so B can still be compiled by
// itself. But usually, that's not the "common" direction you have.
A a1 = new A();
// I make the change here and then trigger a new build
}
}
为什么A需要重新编译一个实现细节,而不是B的接口?
我还尝试了 "hiding" B 在接口 C 后面。我认为这将是分解依赖关系的正确方法(尽管通常很麻烦)。但事实证明它根本没有帮助。
public class A{
public void foo() {
C c1 = C.cFactory();
}
}
public class B implements C {
public void bar() {
// I make the change here and then trigger a new build
}
}
public interface C {
void bar();
public static C cFactory() {
return new B();
}
}
在我看来,我们有这个大的依赖性 blob,我不确定这是否可以合理地改变,即使我认为我们有一个合理设计的代码库。 Android 开发人员中是否存在可以有效改进增量编译的通用最佳实践、指南或设计模式?
我想知道其他人是否有和我们一样的问题,如果没有,你是怎么做的?
问题实际上是我们所有的 classes 都是一个大依赖图的一部分。这显示在引用
Incremental compilation of 476 classes completed in 12.51 secs.
基本上,我接触的任何 class 都会导致重新编译 476 classes。在我们的特定情况下,这是由两种模式引起的。我们在 Android、which I am not sure how to better handle 中使用显式意图。此外,我们使用 Dagger 的方式是将所有 class 连接成一个圆圈。
关于接口问题,我在实现 cFactory()
时犯了一个相当明显的错误。因为这会创建从 C
到 B
的 class 依赖关系,从而从 A
传递到 C
.
以下代码片段打破了从 A
到 B
的依赖关系,但创建了从 B
到 A
的依赖关系。
public class A{
public static void foo(C input) {
input.foo();
}
}
public class B implements C {
public void bar() {
// I make the change here and then trigger a new build
A.foo(this);
}
}
public interface C {
void bar();
}
我改进了构建系统并激活了增量构建和编译,如 this question. To my disappointment, incremental compilation didn't improve build times as much as I expected from reading Gradles blog post 中所述。
经过一些调查,我意识到问题在于,即使我只在应用程序深处的一个小 class 地方添加评论,显然几乎整个代码库都被重建了。事实上,我触摸哪个 class 并不重要,Gradles --debug
输出显示它基本上总是重新编译 476 classes.
Incremental compilation of 476 classes completed in 12.51 secs.
虽然我知道更改文件中的 public static
常量会触发完全重新编译(只是稍微慢一点),但我不明白如何正确分解 class 依赖关系以便增量编译确实有效。确定影响增量编译的 class 依赖项的确切规则是什么?我可以阅读一些示例 here,但它似乎根本不适用于我们的(相当标准的)项目。
我自己的一些测试产生了以下结果:
// One of my main classes that has lots of class dependencies
public class A{
public void foo() {
// This line produces a dependency between A and B. So changing just
// a comment in B triggers recompilation of all classes attached to A
B b1 = new B();
}
}
// A small helper class that I want to change
public class B {
public void bar() {
// This line does not create a dependency, so B can still be compiled by
// itself. But usually, that's not the "common" direction you have.
A a1 = new A();
// I make the change here and then trigger a new build
}
}
为什么A需要重新编译一个实现细节,而不是B的接口?
我还尝试了 "hiding" B 在接口 C 后面。我认为这将是分解依赖关系的正确方法(尽管通常很麻烦)。但事实证明它根本没有帮助。
public class A{
public void foo() {
C c1 = C.cFactory();
}
}
public class B implements C {
public void bar() {
// I make the change here and then trigger a new build
}
}
public interface C {
void bar();
public static C cFactory() {
return new B();
}
}
在我看来,我们有这个大的依赖性 blob,我不确定这是否可以合理地改变,即使我认为我们有一个合理设计的代码库。 Android 开发人员中是否存在可以有效改进增量编译的通用最佳实践、指南或设计模式?
我想知道其他人是否有和我们一样的问题,如果没有,你是怎么做的?
问题实际上是我们所有的 classes 都是一个大依赖图的一部分。这显示在引用
Incremental compilation of 476 classes completed in 12.51 secs.
基本上,我接触的任何 class 都会导致重新编译 476 classes。在我们的特定情况下,这是由两种模式引起的。我们在 Android、which I am not sure how to better handle 中使用显式意图。此外,我们使用 Dagger 的方式是将所有 class 连接成一个圆圈。
关于接口问题,我在实现 cFactory()
时犯了一个相当明显的错误。因为这会创建从 C
到 B
的 class 依赖关系,从而从 A
传递到 C
.
以下代码片段打破了从 A
到 B
的依赖关系,但创建了从 B
到 A
的依赖关系。
public class A{
public static void foo(C input) {
input.foo();
}
}
public class B implements C {
public void bar() {
// I make the change here and then trigger a new build
A.foo(this);
}
}
public interface C {
void bar();
}