如何使用Gradle在Java/Android中正确处理类依赖关系以利用增量编译? [英] How to properly deal with class dependencies to utilize incremental compilation in Java/Android with Gradle?

查看:131
本文介绍了如何使用Gradle在Java/Android中正确处理类依赖关系以利用增量编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我改进了构建系统,并激活了中所述的增量构建和编译问题.令我失望的是,增量编译并没有像阅读 Gradles博客文章中所预期的那样,缩短了构建时间. .

I improved our build system and activated incremental builds and compilation as described in this question. To my disappointment, incremental compilation didn't improve build times as much as I expected from reading Gradles blog post.

经过一番调查,我意识到问题是,即使我仅在应用程序深处的一个小类中添加注释,显然几乎整个代码库都已重建.实际上,我接触哪个类并不重要,Gradles --debug输出表明它基本上总是重新编译476个类.

After some investigation, I realized that the issue is that even though I only add a comment to a small class somewhere deep in the app apparently almost the whole codebase is rebuilt. In fact, it doesn't really matter which class I touch, Gradles --debug output reveals that it basically always recompiles 476 classes.

在12.51秒内完成476个类的增量编译.

Incremental compilation of 476 classes completed in 12.51 secs.

虽然我知道更改后的文件中的public static常量会触发完全重新编译(这只会稍微慢一点),但我不知道如何正确地分解类依赖关系,以便增量编译实际上可以工作.确定影响增量编译的类依赖关系的确切规则是什么?我可以在此处上阅读一些示例,但这似乎不适用于我们(相当标准)项目.

While I understand that public static constants in the changed file trigger a full recompilation (which is only slightly slower), I don't understand how to properly break up class dependencies so that incremental compilation actually works. What are the exact rules to determine class dependencies that affect incremental compilation? I could read about some examples here, but it doesn't appear to apply to our (fairly standard) project at all.

我自己的一些测试得出以下结果:

Some of my own testings yielded the following:

// 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
   }
}

当实现细节(但B的接口没有改变)时,为什么A需要重新编译?

Why does A need recompilation when an implementation detail, but not the interface of B changed?

我还尝试了在接口C后面隐藏"B.我认为这是打破依赖关系的正确方法(尽管通常很麻烦).但是事实证明这根本没有帮助.

I also tried "hiding" B behind an interface C. I thought that would be the proper (even though often times very cumbersome) way to break up the dependencies. But it turns out it didn't help at all.


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开发人员中是否存在可以有效改进增量编译的最佳实践,准则或设计模式?

It appears to me that we have this big dependency blob and I am uncertain this could reasonably be changed even though I would argue we have a reasonably designed codebase. Are there best practices, guidelines or design patterns that are common among Android developers that would effectively improve incremental compilations?

我确实想知道其他人是否和我们有同样的问题,如果不是,您做了什么?

I do wonder whether others have the same problem as we do and if not what did you do?

推荐答案

问题实际上是我们所有的类都是大依赖图的一部分.这显示在报价中

The problem is in fact that all our classes are part of a big dependency graph. This shows in the quote

在12.51秒内完成476个类的增量编译.

Incremental compilation of 476 classes completed in 12.51 secs.

基本上,我接触的任何班级都会导致476个班级的重新编译.在我们的特定情况下,这是由两种模式引起的.我们在Android中使用显式意图,不知道如何更好地处理.此外,我们使用Dagger的方式是将所有类都围成一圈.

Basically, any class I touch causes a recompilation of 476 classes. In our particular case, this is caused by two patterns. We use Explicit Intents in Android, which I am not sure how to better handle. Additionally, we use Dagger in such a way, that we connected all classes in a circle.

关于接口问题,我在实现cFactory()时犯了一个相当明显的错误.这样会创建从CB的类依赖关系,从而从AC的传递.

Concerning the interface problematic I made a rather obvious mistake with implementing the cFactory(). As this creates a class dependency from C to B and thus transitively from A to C.

以下代码片段将依赖关系从A分解为B,但从B分解为A.

The following snippet breaks the dependency from A to B but creates one from B to 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();
}

这篇关于如何使用Gradle在Java/Android中正确处理类依赖关系以利用增量编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆