该错误中描述的问题实际上是大多数 java 编译器和工具的长期限制,与 .class 文件没有维护足够的信息以允许工具正确计算依赖关系有关。Javac 甚至没有走那么远,而是仅在 java 文件比相应的 .class 文件更新时重新编译。这是设计使然,甚至。
我能找到的唯一确定的答案是每次构建时删除所有类文件,使构建不是增量的。您可以通过将其添加到您的 build.xml 来做到这一点:
<target name="-pre-compile" depends="-pre-compile-delete"/>
<target name="-pre-compile-delete">
<!-- Workaround for https://code.google.com/p/android/issues/detail?id=31242 -->
<do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
<delete failonerror="false" dir="${out.classes.absolute.dir}"/>
</do-only-if-manifest-hasCode>
</target>
JDK 的内置工具来解决这个问题是依赖任务。它尝试遍历类文件,并删除传递依赖关系已更改的文件。但是,正如文档中所指出的,depend 有一些限制,这些限制都源于类文件没有包含足够的信息来提供完整的依赖树。
相反,我建议使用dependset task一个更简单但相当健壮的解决方法。如果任何源/jar 较新,我们将删除所有类文件,而不是尝试使用依赖任务进行最小增量编译。我们可能会在实际上不需要时重新编译,但是没有更改的构建仍然更快,并且我们不会在需要时无意中跳过编译。
<target name="-pre-compile" depends="-pre-compile-dependset" />
<target name="-pre-compile-dependset">
<!-- Alternative workaround for https://code.google.com/p/android/issues/detail?id=31242 -->
<echo>Deleting all class files if newer sources (java or jars) are found...</echo>
<do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
<!-- The names of these properties suggest they are single directories, but -->
<!-- some projects with Android.mk files treat them like paths (with multiple dirs). -->
<!-- Massage these paths get all the files inside multiple dirs. -->
<path id="project.all.sources.path">
<pathelement path="${source.absolute.dir}"/>
<pathelement path="${gen.absolute.dir}"/>
</path>
<!-- convert project.all.sources.path to project.all.sources.list -->
<pathconvert
refid="project.all.sources.path"
property="project.all.sources.list"
pathsep=","
dirsep="/">
<!-- Make the path elements relative to basedir and glob to match all files -->
<!-- The result will look like: "src/**,gen/**" -->
<chainedmapper>
<filtermapper>
<replacestring from="${basedir}/" to=""/>
</filtermapper>
<regexpmapper from="^(.*)" to="\1/**"/>
</chainedmapper>
</pathconvert>
<dependset verbose="true">
<sources>
<!-- merge the project's own classpath and the tested project's classpath -->
<path refid="project.all.jars.path" />
<path refid="tested.project.classpath" />
<!-- All source files -->
<fileset dir="${basedir}" includes="${project.all.sources.list}" />
</sources>
<targets>
<fileset dir="${out.classes.absolute.dir}"/>
</targets>
</dependset>
</do-only-if-manifest-hasCode>
</target>
该解决方案足够可靠,我相信它最终可以合并到 sdk 构建中。