前言
本小节讲解编译优化中关于R文件优化与kotlin 1.6.10的问题
我们首先抛出一个来自官方的问题 问题链接
我们发现修改布局中某个控件id,在kotlin 1.6.10中kaptgenerate任务与compile任务会触发全量编译
kotlin 1.6.10 引起KaptGenerate全量问题
要探索这个问题其实要前提了解部分增量源码机制
哪些task的输入可以被增量? 被@Incremental与@SkipWhenEmpty 标注的输入可以被增量 举例如下:
abstract class MyTask : DefaultTask() {
@OutputDirectory
@Incremental
abstract fun getOutputDir(): DirectoryProperty?
@OutputDirectory
@SkipWhenEmpty
abstract fun getOutputDir2(): DirectoryProperty?
@InputFiles
abstract fun getSourceFiles(): ConfigurableFileCollection?
@TaskAction
fun action(inputChange: InputChanges) {
}
}
在Gradle 运行时DefaultExecutionStateChangeDetector 这个类中会进行增量判断
public class DefaultExecutionStateChangeDetector implements ExecutionStateChangeDetector {
@Override
public ExecutionStateChanges detectChanges(AfterPreviousExecutionState lastExecution, BeforeExecutionState thisExecution, Describable executable, IncrementalInputProperties incrementalInputProperties) {
ChangeContainer previousSuccessState = new PreviousSuccessChanges(
lastExecution.isSuccessful());
ChangeContainer implementationChanges = new ImplementationChanges(
lastExecution.getImplementation(), lastExecution.getAdditionalImplementations(),
thisExecution.getImplementation(), thisExecution.getAdditionalImplementations(),
executable);
ChangeContainer inputPropertyChanges = new PropertyChanges(
lastExecution.getInputProperties(),
thisExecution.getInputProperties(),
"Input",
executable);
ChangeContainer inputPropertyValueChanges = new InputValueChanges(
lastExecution.getInputProperties(),
thisExecution.getInputProperties(),
executable);
ChangeContainer inputFilePropertyChanges = new PropertyChanges(
lastExecution.getInputFileProperties(),
thisExecution.getInputFileProperties(),
"Input file",
executable);
InputFileChanges nonIncrementalInputFileChanges = incrementalInputProperties.nonIncrementalChanges(
lastExecution.getInputFileProperties(),
thisExecution.getInputFileProperties()
);
ChangeContainer outputFilePropertyChanges = new PropertyChanges(
lastExecution.getOutputFileProperties(),
thisExecution.getOutputFileProperties(),
"Output",
executable);
OutputFileChanges outputFileChanges = new OutputFileChanges(
lastExecution.getOutputFileProperties(),
thisExecution.getOutputFileProperties()
);
ChangeContainer rebuildTriggeringChanges = errorHandling(executable, new SummarizingChangeContainer(
previousSuccessState,
implementationChanges,
inputPropertyChanges,
inputPropertyValueChanges,
outputFilePropertyChanges,
outputFileChanges,
inputFilePropertyChanges,
nonIncrementalInputFileChanges
));
ImmutableList<String> rebuildReasons = collectChanges(rebuildTriggeringChanges);
if (!rebuildReasons.isEmpty()) {
return new NonIncrementalDetectedExecutionStateChanges(
rebuildReasons,
thisExecution.getInputFileProperties(),
incrementalInputProperties
);
} else {
InputFileChanges directIncrementalInputFileChanges = incrementalInputProperties.incrementalChanges(
lastExecution.getInputFileProperties(),
thisExecution.getInputFileProperties()
);
InputFileChanges incrementalInputFileChanges = errorHandling(executable, caching(directIncrementalInputFileChanges));
ImmutableList<String> incrementalInputFileChangeMessages = collectChanges(incrementalInputFileChanges);
return new IncrementalDetectedExecutionStateChanges(
incrementalInputFileChangeMessages,
thisExecution.getInputFileProperties(),
incrementalInputFileChanges,
incrementalInputProperties
);
}
}
}
其中我们来拆解一下这个类中重要的代码段
ChangeContainer rebuildTriggeringChanges = errorHandling(executable, new SummarizingChangeContainer(
previousSuccessState,
implementationChanges,
inputPropertyChanges,
inputPropertyValueChanges,
outputFilePropertyChanges,
outputFileChanges,
inputFilePropertyChanges,
nonIncrementalInputFileChanges
));
ImmutableList<String> rebuildReasons = collectChanges(rebuildTriggeringChanges);
if (!rebuildReasons.isEmpty()) {
return new NonIncrementalDetectedExecutionStateChanges(
rebuildReasons,
thisExecution.getInputFileProperties(),
incrementalInputProperties
);
} else {
InputFileChanges directIncrementalInputFileChanges = incrementalInputProperties.incrementalChanges(
lastExecution.getInputFileProperties(),
thisExecution.getInputFileProperties()
);
InputFileChanges incrementalInputFileChanges = errorHandling(executable, caching(directIncrementalInputFileChanges));
ImmutableList<String> incrementalInputFileChangeMessages = collectChanges(incrementalInputFileChanges);
return new IncrementalDetectedExecutionStateChanges(
incrementalInputFileChangeMessages,
thisExecution.getInputFileProperties(),
incrementalInputFileChanges,
incrementalInputProperties
);
在kotlin 1.6.10会将R.jar文件改动放入nonIncrementalInputFileChanges中,且对应的字段为$1,如果搜索整个源码会发现找不到这个字段,具体原因是这个字段是匿名动态赋值 到KaptGernerate任务中如下代码:
Task myTask =tasks.maybeCreate("hello")
myTask.inputs.file("xxx/R.jar")
解决方案字节码修改相关代码即可,但是我最后发现1.6.20修复了这个问题
R 文件引起的compile全量问题
在AGP 3.6版本后不在生成R.java而是直接生成R.jar这样会加速整个编译过程,但是Gradle当前无法感知内部jar文件变化(答案来自官方论坛)。 在最新版本的kotlin中也没有解决相关问题。
因此笔者自己用了奇淫技巧去规避整个问题。
AGP的GenerateLibraryRFileTask 生产出R.jar文件与R.txt.您可以直接修改这个Task还原会AGP之前的版本即可,在赋值给Compile任务的输入即可 但是这个方案实现比较麻烦最后因为没有时间就放弃了。于是我们可以利用R.jar 和R.txt 自己生产一个R.java 即可,但是需要中间Task作为桥接:
修正后的基准测试对比图
|