精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

深入理解 Android Studio Sync 流程

精選
移動開發 Android
本文首先介紹了 Android Studio Sync 流程中各個角色的作用及聯系,對 Sync 有一個較清晰的整體認識,然后從源碼角度深入分析從觸發 Sync 入口到 Gradle 構建結束的階段,并詳細解釋了 Gradle Model、BuildAction 等關鍵概念

1. 初識 Sync

我們一般會把 Sync 理解為 Android Studio 的準備階段,包括解析工程配置信息、下載遠程依賴到本地、更新代碼索引等準備工作,當修改 gradle build 文件后,需要重新 Sync 將 Gradle 構建配置信息同步到 IDE,進而使 IDE 的功能及時應用新的構建配置,這些功能包括項目的 Gradle Task 列表展示、依賴信息展示等等。Sync 是 Android Studio 中獨有的概念,當通過 Gradle 命令行程序構建 Android 應用時,只會經歷 Gradle 定義的 Initialization、Configuration 和 Execution 生命周期,根本沒有 Sync 的概念。Android Studio 的 Sync 階段涉及到 IDE、Gradle、Plugin 等多個角色,梳理清楚這些角色各自的作用和聯系,才能清晰理解 Sync 的整體架構,下面分別來介紹這些角色:

圖片

IDE 層面:Android Studio 基于 IntelliJ IDEA 擴展而來,復用了 IntelliJ IDEA 強大的代碼編輯器和開發者工具等 IDE 基礎能力,在此之上 Android Studio 提供了更多提高 Android 構建效率的功能,如 Android 模擬器、代碼模版等等。另外 Android Studio 也將自身專業的 Android 應用開發能力反哺給 IntelliJ IDEA,以 Android IDEA Plugin 的形式,使 IntelliJ IDEA 支持 Android 應用開發,二者互相賦能,相輔相成。

Gradle 層面:Gradle 是一個靈活而強大的開源構建系統,它除了提供跨平臺的可執行程序支持命令行執行 Gradle 構建外,還專門提供了 Gradle Tooling API 編程 SDK,供外部更方便、更緊密的將 Gradle 構建能力嵌入到 IDE 中,IntelliJ IDEA、Eclipse、VSCode 等 IDE 都采用了這種方式。在 Gradle 源碼中也有專門服務于 IntelliJ IDEA、Eclipse 等 IDE 的代碼模塊,構建工具和 IDE 兩個角色之間同樣是互相賦能,強強聯合。

Plugin 層面:Plugin 層面包括 Android IDEA Plugin 和 Android Gradle Plugin,Android IDEA Plugin 為 IntelliJ IDEA/Android Studio 拓展了 Android 應用開發能力;Android Gradle Plugin 為 Gradle 拓展了 Android 應用構建能力。谷歌通過這兩個 Plugin 將現代成熟優秀的 IDE 開發能力和構建工具聯合在一起為 Android 所用,相比于早期 Eclipse 加 ANT 構建的開發方式,大幅提升了 Android 應用開發效率和體驗。

2. Sync 流程分析

了解了 Sync 階段涉及到的角色以及它們之間的關系后,接下來深入 Android Studio 源碼,從代碼層面梳理清楚 Sync 的關鍵流程。

2.1 Android Studio 源碼分析

2.1.1 功能入口及準備

在 Android Studio 中觸發 Sync 操作后,會從最上層的入口類 GradleSyncInvoker 調用到實際負責解析 Gradle 構建信息的 GradleProjectResolver,調用鏈如下圖所示:

圖片

調用過程中涉及到的關鍵類:

GradleSyncInvoker:觸發 Sync 的入口類,在 Android Studio 多處需要執行 Sync 的地方,都是通過調用此類的 requestProjectSync 方法來觸發的

ExternalSystemUtil:GradleSyncInvoker、GradleSyncExecutor 等類是專門針對 Sync 功能的封裝,Sync 是 Android Studio 中獨有的操作,在 IntelliJ IDEA 中并沒有 Sync 的概念,IntelliJ IDEA 通過 [Reload All Gradle Projects] 操作來觸發解析工程的 Gradle 構建信息,直接從 ExternalSystemUtil 類開始執行

GradleProjectResolver:負責具體執行 Sync,其中 resolveProjectInfo 方法是具體執行 Sync 邏輯的地方,該方法的定義如下:

public DataNode<ProjectData> resolveProjectInfo(
@NotNull ExternalSystemTaskId id,
@NotNull String projectPath,
boolean isPreviewMode,
@Nullable S settings,
@NotNull ExternalSystemTaskNotificationListener listener)
throws ExternalSystemException, IllegalArgumentException, IllegalStateException
  • id:本次 Sync 操作的唯一標識,后續可通過調用 GradleProjectResolver 中的 cancelTask 方法取消本次 Sync 任務
  • projectPath:工程絕對路徑
  • settings:Sync 工程的配置參數,可設置 Java 版本等
  • listener:用于監聽此次 Sync 的過程及結果
  • isPreviewMode:是否要啟用預覽模式,Android Studio 首次打開未知來源項目時,會讓開發者選擇項目的打開方式,如下圖,若選擇 [Stay in Safe Mode] 則會以“預覽模式”運行項目,表示 IDE 僅可以瀏覽項目的源代碼,不會執行或解析任何構建任務和腳本

圖片

進入 GradleProjectResolver 的 resolveProjectInfo 方法中后,首先會對預覽模式進行處理,如下代碼所示,如果是預覽模式,則會簡單構造出對應的工程數據結構后立馬返回,不進行任何的解析行為:

if (isPreviewMode) {
String projectName = new File(projectPath).getName();
ProjectData projectData = new ProjectData(GradleConstants.SYSTEM_ID, projectName, projectPath, projectPath);
DataNode<ProjectData> projectDataNode = new DataNode<>(ProjectKeys.PROJECT, projectData, null);
......
return projectDataNode;
}

使用 Android Studio/IntelliJ IDEA 打開工程時,除了指定工程所在根目錄,還可以指定 Gradle 配置文件,這個邏輯在源碼中也有所體現:

if (projectPathFile.isFile() && projectPath.endsWith(GradleConstants.EXTENSION) && projectPathFile.getParent() != null) {
projectDir = projectPathFile.getParent();
if (settings != null) {
List<String> arguments = settings.getArguments();
if (!arguments.contains("-b") && !arguments.contains("--build-file")) {
settings.withArguments("-b", projectPath);
}
}
} else {
projectDir = projectPath;
}

可以看到如果打開的不是工程根目錄而是配置文件,那就會把該配置文件所在的目錄作為工程路徑,并且會通過 --build-file 參數來指定配置文件,后續會傳入到 Gradle 中。對工程初步處理后,接著通過 Gradle Tooling API 獲取工程的 BuildEnvironment:

ModelBuilder<BuildEnvironment> modelBuilder = connection.model(BuildEnvironment.class);

調用 Gradle Tooling API 時其內部會自動下載項目配置版本的 Gradle,也就是說,上面代碼中獲取 BuildEnvironment Model 的調用本身確保了 Gradle 的下載,即將 /grade/wrapper/gradle-wrapper.properties 里 distributionUrl 指定的 Gradle 下載到 GRADLE_HOME/wrapper/dists 下。

BuildEnvironment 是 Gradle 提供的 Gradle Model,Gradle Model 是一個非常重要的概念,當 IDE 通過 Gradle Tooling API 和 Gradle 交互時,傳輸的就是各種各樣的 Model,比如 Gradle 自帶的 GradleProject 、 BuildEnvironment 等,另外也可以在 Gradle Plugin 中通過 ToolingModelBuilderRegistry 注冊自定義的 Model,如 Android Gradle Plugin 中注冊了 AndroidProject Model,那就可以通過 Gradle Tooling API 獲取 Android 項目特有的 AndroidProject Model,從而獲取由 Android Gradle Plugin 提供的 Android 應用相關工程信息。

2.1.2 配置 BuildAction

繼續分析 Android Studio Sync 源碼,接下來構造了一個 ProjectImportAction,它實現了 Gradle Tooling API 中的 BuildAction 接口,BuildAction 定義如下:

public interface BuildAction<T> extends Serializable {

T execute(BuildController controller);
}

BuildAction 是即將傳入到 Gradle 構建進程中執行的行為,并且可將結果數據序列化返回給調用方。這個 BuildAction至關重要,它是實際和 Gradle 通信的地方,其中實現了組織生成工程信息、下載依賴等功能,是 Sync 流程中的核心邏輯。BuildAction 再配合 Gradle Tooling API 中的 BuildActionExecuter,就可以將 BuildAction 交由 Gradle 觸發執行了,在執行之前,需先通過 BuildActionExecuter 配置 JVM 參數、Gradle 命令行參數以及環境變量等構建信息:

private static void configureExecutionArgumentsAndVmOptions(@NotNull GradleExecutionSettings executionSettings,
@NotNull DefaultProjectResolverContext resolverCtx,
boolean isBuildSrcProject) {
executionSettings.withArgument("-Didea.sync.active=true");
if (resolverCtx.isResolveModulePerSourceSet()) {
executionSettings.withArgument("-Didea.resolveSourceSetDependencies=true");
}
if (!isBuildSrcProject) {
for (GradleBuildParticipant buildParticipant : executionSettings.getExecutionWorkspace().getBuildParticipants()) {
executionSettings.withArguments(GradleConstants.INCLUDE_BUILD_CMD_OPTION, buildParticipant.getProjectPath());
}
}
GradleImportCustomizer importCustomizer = GradleImportCustomizer.get();
GradleProjectResolverUtil.createProjectResolvers(resolverCtx).forEachOrdered(extension -> {
if (importCustomizer == null || importCustomizer.useExtraJvmArgs()) {

ParametersList parametersList = new ParametersList();
for (Pair<String, String> jvmArg : extension.getExtraJvmArgs()) {
parametersList.addProperty(jvmArg.first, jvmArg.second);
}
executionSettings.withVmOptions(parametersList.getParameters());
}

executionSettings.withArguments(extension.getExtraCommandLineArgs());
});
}

上述代碼較多,我們先只關注于 GradleExecutionSettings 的 withArgument 和 withVmOptions 方法,它們分別負責收集 Gradle 命令行參數和 JVM 參數。從代碼中可以看出,這些 Gradle 命令行參數及 JVM 參數大多數是從 extension 中收集而來,這里的 extension 是指 IntelliJ IDEA Plugin 中的擴展,和擴展點結合使用,可擴展 IntelliJ IDEA 平臺特性或其他 IntelliJ IDEA Plugin 的功能特性,舉個例子,Gradle IDEA Plugin 提供了工程解析的擴展點:

<extensionPoint 
qualifiedName="org.jetbrains.plugins.gradle.projectResolve"
interface="org.jetbrains.plugins.gradle.service.project.GradleProjectResolverExtension"/>

Android IDEA Plugin 中實現了此擴展點,提供了 Android 工程解析的拓展:

<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<projectResolve implementation=
"com.android.tools.idea.gradle.project.sync.idea.AndroidGradleProjectResolver"
order="first"/>
......
</extensions>

接著來看 BuildAction 的參數配置邏輯,最終設置 JVM 參數的地方在 GradleExecutionHelper 的 prepare 方法中:

List<String> jvmArgs = settings.getJvmArguments();
BuildEnvironment buildEnvironment = getBuildEnvironment(connection, id, listener, (CancellationToken)null, settings);
if (!jvmArgs.isEmpty()) {

Collection<String> merged;
if (buildEnvironment != null) {


BuildIdentifier buildIdentifier = getBuildIdentifier(buildEnvironment);
List<String> buildJvmArguments = buildIdentifier == null || "buildSrc".equals(buildIdentifier.getRootDir().getName())
? ContainerUtil.emptyList()
: buildEnvironment.getJava().getJvmArguments();
merged = mergeBuildJvmArguments(buildJvmArguments, jvmArgs);
} else {
merged = jvmArgs;
}
List<String> filteredArgs = ContainerUtil.mapNotNull(merged, s -> StringUtil.isEmpty(s) ? null : s);
operation.setJvmArguments(ArrayUtilRt.toStringArray(filteredArgs));
}

如上代碼所示,JVM 參數的配置邏輯很簡單:將之前從一系列 GradleProjectResolve 擴展中收集的、存放在 GradleExecutionSettings 中的 JVM 參數和 BuildEnvironment 中的 JVM 參數合并,然后調用 BuildActionExecuter 的 setJvmArguments 方法,將 JVM 參數設置給 BuildAction。Gradle 命令行參數同樣是在 GradleExecutionHelper 的 prepare 方法中配置:

...
List<String> filteredArgs = new ArrayList<>();
if (!settings.getArguments().isEmpty()) {
String loggableArgs = StringUtil.join(obfuscatePasswordParameters(settings.getArguments()), " ");
LOG.info("Passing command-line args to Gradle Tooling API: " + loggableArgs);

filteredArgs.addAll(ContainerUtil.mapNotNull(settings.getArguments(), s -> StringUtil.isEmpty(s) ? null : s));
...
}
filteredArgs.add("-Didea.active=true");
filteredArgs.add("-Didea.version=" + getIdeaVersion());
operation.withArguments(ArrayUtilRt.toStringArray(filteredArgs));

對于一個最簡單的 Kotlin App Demo 工程,Gradle 命令行參數如下:

來源

參數

Android Studio 源碼

--init-script
/private/var/folders/_4/j3fdr4nd0x7cf17yvt20f5c00000gp/T/ijmapper.gradle
-Didea.sync.active=true
-Didea.resolveSourceSetDependencies=true
-Porg.gradle.kotlin.dsl.provider.cid=676307056703202
-Pkotlin.mpp.enableIntransitiveMetadataConfiguration=true
--init-script/private/var/folders/_4/j3fdr4nd0x7cf17yvt20f5c00000gp/T/ijinit3.gradle
-Didea.active=true
-Didea.version=2021.3

Android IDEA Plugin 擴展:com.android.tools.idea.gradle.project.sync.idea.AndroidGradleProjectResolver

--init-script
/private/var/folders/_4/j3fdr4nd0x7cf17yvt20f5c00000gp/T/sync.studio.tooling4770.gradle
-Djava.awt.headless=true
--stacktrace-Pandroid.injected.build.model.only=true
-Pandroid.injected.build.model.only.advanced=true
-Pandroid.injected.invoked.from.ide=true
-Pandroid.injected.build.model.only.versioned=3
-Pandroid.injected.studio.version=10.4.2
-Pandroid.injected.build.model.disable.src.download=true
-Pidea.gradle.do.not.build.tasks=true

Kotlin IDEA Plugin 擴展:org.jetbrains.kotlin.idea.gradleJava.scripting.importing.KotlinDslScriptModelResolver

-Dorg.gradle.kotlin.dsl.provider.mode=classpath

Kotlin IDEA Plugin 擴展:org.jetbrains.kotlin.idea.gradleJava.scripting.importing.KotlinDslScriptModelResolver

-Porg.gradle.kotlin.dsl.provider.cid=676307056703202

Kotlin IDEA Plugin 擴展:org.jetbrains.kotlin.idea.gradleJava.configuration.KotlinMPPGradleProjectResolver

-Pkotlin.mpp.enableIntransitiveMetadataConfiguration=true

重點關注其中的 --init-script 命令行參數,它可以指定一個初始化腳本,初始化腳本會在項目構建腳本之前執行。初始化腳本是 Gradle 提供的一個非常靈活的機制,除了命令行配置,還可以將初始化腳本命名為 init.gradle 放置到 USER_HOME/.gradle/ 下進行配置。初始化腳本允許自定義所有項目的構建邏輯,比如定義特定機器上所有項目的 JDK 路徑等環境信息。在上述 Kotlin App Demo 工程中,Android IDEA Plugin 擴展配置了一個初始化腳本,內容如下:

initscript {
dependencies {
classpath files([mapPath('/Users/bytedance/IDE/intellij-community/out/production/intellij.android.gradle-tooling'), mapPath('/Users/bytedance/IDE/intellij-community/out/production/intellij.android.gradle-tooling.impl'), mapPath('/Users/bytedance/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.5.10-release-945/kotlin-stdlib-1.5.10-release-945.jar')])
}
}
allprojects {
apply plugin: com.android.ide.gradle.model.builder.AndroidStudioToolingPlugin
}

初始化腳本中對所有項目應用了 AndroidStudioToolingPlugin 插件,此插件中通過 ToolingModelBuilderRegistry 注冊了 AdditionalClassifierArtifactsModel,這個 Gradle Model 中實現了下載依賴 sources 和 javadoc 的功能:

class AdditionalClassifierArtifactsModelBuilder : ParameterizedToolingModelBuilder<AdditionalClassifierArtifactsModelParameter> {
...

也就是說,Android IDEA Plugin 提供了依賴 sources 和 javadoc 的下載功能,當通過 Gradle Tooling API 獲取 AdditionalClassifierArtifactsModel Gradle Model 的時候,會觸發依賴的 sources 和 javadoc 下載。

分析完 BuildAction 的 JVM 參數和 Gradle 命令行參數配置流程后,最后來看 BuildAction 環境變量的配置,最終配置的地方在 GradleExecutionHelper 的 setupEnvironment 方法中:

GeneralCommandLine commandLine = new GeneralCommandLine();
commandLine.withEnvironment(settings.getEnv());
commandLine.withParentEnvironmentType(
settings.isPassParentEnvs() ? GeneralCommandLine.ParentEnvironmentType.CONSOLE : GeneralCommandLine.ParentEnvironmentType.NONE);
Map<String, String> effectiveEnvironment = commandLine.getEffectiveEnvironment();
operation.setEnvironmentVariables(effectiveEnvironment);

GeneralCommandLine 中包括當前 Java 進程所有的環境變量,其他環境變量和 JVM 參數類似都被收集在 GradleExecutionSettings 中,Android Studio 會先將其他環境變量與 GeneralCommandLine 中的環境變量合并,然后配置給 BuildAction. 對于不進行任何配置的默認 sync 行為,GradleExecutionSettings 中環境變量為空,全由 GeneralCommandLine 提供。

2.1.3 執行 BuildAction

分析完 BuildAction 的配置邏輯后,接著來看 BuildAction 中具體做了哪些事。BuildAction 中的行為不再處于 Android Studio IDE 進程了,而是在 Gradle 構建進程中執行。IDE 通過 Gradle Tooling API 與 Gradle 交互時,主要媒介是 Gradle Model,BuildAction 中也不例外。BuildAction 的具體執行邏輯見其實現類 ProjectImportAction 中的 execute 方法,我們只關注此方法中與 Gradle Model 相關的代碼:

public AllModels execute(final BuildController controller) {
...
fetchProjectBuildModels(wrappedController, isProjectsLoadedAction, myGradleBuild);
addBuildModels(wrappedController, myAllModels, myGradleBuild, isProjectsLoadedAction);
...
}

BuildAction 中調用 fetchProjectBuildModels 和 addBuildModels 方法獲取 Gradle Model。先來分析 fetchProjectBuildModels 方法,該方法中進一步調用 getProjectModels 方法:

private List<Runnable> getProjectModels(@NotNull BuildController controller,
@NotNull final AllModels allModels,
@NotNull final BasicGradleProject project,
boolean isProjectsLoadedAction) {
...
Set<ProjectImportModelProvider> modelProviders = getModelProviders(isProjectsLoadedAction);
for (ProjectImportModelProvider extension : modelProviders) {
extension.populateProjectModels(controller, project, modelConsumer);
}
...
}

如上代碼所示,通過 ProjectImportModelProvider 的 populateProjectModels 方法進一步去獲取 Gradle Model。BuildAction 的 addBuildModels 方法與此十分相似:

private void addBuildModels(@NotNull final ToolingSerializerAdapter serializerAdapter,
@NotNull BuildController controller,
@NotNull final AllModels allModels,
@NotNull final GradleBuild buildModel,
boolean isProjectsLoadedAction) {
Set<ProjectImportModelProvider> modelProviders = getModelProviders(isProjectsLoadedAction);
for (ProjectImportModelProvider extension : modelProviders) {
extension.populateBuildModels(controller, buildModel, modelConsumer);
}
...
}

可以看到同樣是交給了 ProjectImportModelProvider 去獲取 Gradle Model,不同的是,前者調用的 populateProjectModels,此處調用的是 populateBuildModels 方法,ProjectImportModelProvider 的作用就是生成 Gradle Model。ProjectImportModelProvider 同 JVM 參數和 Gradle 命令行參數一樣,都是由一系列 Gradle IDEA Plugin 擴展提供,如下代碼所示:

for (GradleProjectResolverExtension resolverExtension = tracedResolverChain;
resolverExtension != null;
resolverExtension = resolverExtension.getNext()) {
...
ProjectImportModelProvider modelProvider = resolverExtension.getModelProvider();
if (modelProvider != null) {
projectImportAction.addProjectImportModelProvider(modelProvider);
}
ProjectImportModelProvider projectsLoadedModelProvider = resolverExtension.getProjectsLoadedModelProvider();
if (projectsLoadedModelProvider != null) {
projectImportAction.addProjectImportModelProvider(projectsLoadedModelProvider, true);
}
}

對于 Android 工程來說,重點關注 Android IDEA Plugin,它提供的 ProjectImportModelProvider 的實現類為 AndroidExtraModelProvider,該實現類的 populateProjectModels 方法如下:

override fun populateProjectModels(controller: BuildController,
projectModel: Model,
modelConsumer: ProjectImportModelProvider.ProjectModelConsumer) {
controller.findModel(projectModel, GradlePluginModel::class.java)
?.also { pluginModel -> modelConsumer.consume(pluginModel, GradlePluginModel::class.java) }
controller.findModel(projectModel, KaptGradleModel::class.java)
?.also { model -> modelConsumer.consume(model, KaptGradleModel::class.java) }
}

此方法中通過 Gradle Tooling API 獲取了 GradlePluginModel 和 KaptGradleModel 兩個 Gradle Model,GradlePluginModel 中提供了項目已應用的 Gradle Plugin 信息;KaptGradleModel 提供了 Kotlin 注解處理相關信息。接著來看 populateBuildModels 方法:

override fun populateBuildModels(
controller: BuildController,
buildModel: GradleBuild,
consumer: ProjectImportModelProvider.BuildModelConsumer) {
populateAndroidModels(controller, buildModel, consumer)
populateProjectSyncIssues(controller, buildModel, consumer)
}

其中分別調用了 populateAndroidModels 和 populateProjectSyncIssues 方法,先來看 populateProjectSyncIssues 方法,它會進一步通過 Gradle Tooling API 獲取 ProjectSyncIssues Gradle Model,用于收集 Sync 過程中出現的問題。再來分析 populateAndroidModels 方法,它在整個 Sync 過程中至關重要,其中通過 Gradle Tooling API 獲取了 Android 工程相關的 Gradle Model:

val androidModules: MutableList<AndroidModule> = mutableListOf()
buildModel.projects.forEach { gradleProject ->
findParameterizedAndroidModel(controller, gradleProject, AndroidProject::class.java)?.also { androidProject ->
consumer.consumeProjectModel(gradleProject, androidProject, AndroidProject::class.java)
val nativeAndroidProject = findParameterizedAndroidModel(controller, gradleProject, NativeAndroidProject::class.java)?.also {
consumer.consumeProjectModel(gradleProject, it, NativeAndroidProject::class.java)
}
androidModules.add(AndroidModule(gradleProject, androidProject, nativeAndroidProject))
}
}

如上代碼所示,分別獲取了由 Android Gradle Plugin 注冊的兩個 Gradle Model AndroidProject 和 NativeAndroidProject,AndroidProject 中包括 Android 應用的 BuildType、Flavors、Variant、Dependency 等關鍵信息;NativeAndroidProject 中包括 NDK、NativeToolchain 等 Android C/C++ 項目相關信息。獲取了最關鍵的 AndroidProject 和 NativeAndroidProject 后,接著是對單 Variant Sync 的處理:

if (syncActionOptions.isSingleVariantSyncEnabled) {
chooseSelectedVariants(controller, androidModules, syncActionOptions)
}

怎么理解單 Variant Sync 呢?Variant 指 Android 應用的產物變體,比如最簡單的 Debug 和 Release 版本應用包。Variant 對應于一套構建配置,與項目源碼結構、依賴列表相關聯。Android 應用可能有多個 Variant,如果在 Sync 時構造所有 Variant,整體耗時可能極長,所以 Android Studio Sync 默認只會構造一個 Variant,并支持 Variant 切換功能。如果啟用了單 Variant Sync,前面獲取 AndroidProject 時會傳入過濾參數,告知 Android Gradle Plugin 構造 AndroidProject 時無需構造 Variant 信息。

2.2 Sync 流程梳理

2.2.1 Android Studio 視角

Android Studio Sync 流程的源碼龐大而繁雜,本文著重分析了從觸發 Sync 入口到 Gradle 構建結束的階段,后續還有對 Gradle 數據的處理,以及語言能力模塊基于 Gradle 數據進行代碼索引的流程,而語言能力又是一個大型而復雜的模塊,本文就不再繼續展開。

上文源碼分析部分將觸發 Sync 入口到 Gradle 構建結束劃分為 Sync 功能入口及準備、配置 BuildAction 以及執行 BuildAction,整體流程如下圖所示:

圖片

2.2.2 Gradle 視角

上面都是以 IDE 視角去分析 Android Studio Sync,整體流程較復雜,接下來以 Gradle 視角去梳理 Sync 流程,著重關注 Gradle 側的行為:

圖片

如上圖,對于 Gradle 來說,Sync 流程中 Android Studio 會通過 Gradle Tooling API 從 Gradle 側獲取一系列所需的 Gradle Model,除 Gradle 自身外,Gradle Plugin 也可以提供自定義的 Gradle Model。另外 Sync 流程中 Gradle 會經歷自身定義的生命周期,聚焦此視角梳理流程如下:

圖片

當通過 BuildAction 獲取 Gradle Model 時會觸發 Gradle 的構建行為,Gradle 構建會經歷自身生命周期定義的 Initialization、Configuration 和 Execution 階段。

3. 總結

本文首先介紹了 Android Studio Sync 流程中各個角色的作用及聯系,對 Sync 有一個較清晰的整體認識,然后從源碼角度深入分析從觸發 Sync 入口到 Gradle 構建結束的階段,并詳細解釋了 Gradle Model、BuildAction 等關鍵概念,最后分別從 Android Studio 視角和 Gradle 視角對 Sync 流程進行了整體梳理。

通過對 Android Studio Sync 流程的深入分析,除了對 Sync 功能的實現原理深度掌握外,對其意義也有了更深的理解。Sync 是 Android Studio 定義的一個 IDE 準備階段,在這個準備階段中,需提前準備好關鍵的 IDE 功能,而這些功能要達到可用狀態,需要獲取其必需的數據。基于這個角度,對 Sync 流程的優化方向也有了一定啟發:首先從產品層面出發考慮 Sync 階段的定義,不是開發者真正必需的功能都可以考慮省略或延后準備;然后確認必需功能所需的最小數據集,不必需的數據都可以省略;最后針對必需數據,通過更高效的實現或緩存,找到最快的獲取方式。

4. 參考鏈接

https://mp.weixin.qq.com/s/cftj6WueoHlLh-So9REEXQ

https://developer.android.com/studio/intro

https://android.googlesource.com/platform/tools/base/+/studio-master-dev

https://plugins.jetbrains.com/developers

責任編輯:未麗燕 來源: 字節跳動技術團隊
相關推薦

2022-09-01 08:08:35

Android移動操作系統

2016-12-08 15:36:59

HashMap數據結構hash函數

2010-06-01 15:25:27

JavaCLASSPATH

2020-07-21 08:26:08

SpringSecurity過濾器

2024-05-23 08:02:23

2017-05-03 17:00:16

Android渲染機制

2021-09-16 06:44:04

Android進階流程

2021-09-17 06:55:50

AndroidLayoutView

2009-09-25 09:14:35

Hibernate日志

2021-02-17 11:25:33

前端JavaScriptthis

2023-10-19 11:12:15

Netty代碼

2013-09-22 14:57:19

AtWood

2017-08-15 13:05:58

Serverless架構開發運維

2025-05-06 00:43:00

MySQL日志文件MIXED 3

2017-01-10 08:48:21

2020-09-23 10:00:26

Redis數據庫命令

2025-06-05 05:51:33

2024-02-21 21:14:20

編程語言開發Golang

2019-06-25 10:32:19

UDP編程通信

2021-10-26 17:52:52

Android插件化技術
點贊
收藏

51CTO技術棧公眾號

一区二区三区在线资源| 色欲久久久天天天综合网| 欧美电影免费播放| 91精品国产欧美一区二区| 隔壁人妻偷人bd中字| 欧美777四色影视在线| 捆绑调教一区二区三区| 欧美激情性做爰免费视频| 亚洲天堂视频一区| 亚洲成人1区| 午夜日韩在线电影| 一区二区成人国产精品 | 91成人国产精品| av不卡在线免费观看| 午夜福利视频一区二区| 久久99精品久久久久久动态图| 欧美激情在线狂野欧美精品| 香蕉视频久久久| 试看120秒一区二区三区| 色欧美88888久久久久久影院| 国产又粗又大又爽的视频| 玖玖综合伊人| 国产成人精品午夜视频免费| 国产精品国产三级国产aⅴ9色 | 成人福利在线| 99久久婷婷国产综合精品电影| 国产日韩中文字幕在线| 国产微拍精品一区| 国产精品成人一区二区网站软件| 亚洲天堂男人天堂女人天堂| 中文字幕在线播放一区| www久久久| 欧美三级日本三级少妇99| 男人日女人逼逼| 亚洲淫性视频| 中文字幕一区视频| 色视频一区二区三区| 欧美少妇另类| 成人国产电影网| 91影院未满十八岁禁止入内| 在线播放成人av| 丝瓜av网站精品一区二区| 97成人超碰免| 日韩女优在线观看| 国内精品久久久久久久影视麻豆| 久久亚洲精品网站| 91n在线视频| 久久香蕉国产| 日韩一区二区三区在线播放| 微拍福利一区二区| 欧美另类69xxxxx| 亚洲一区二区久久久| 中文字幕一区二区三区人妻| 日韩av三区| 亚洲精品mp4| 国产又粗又猛又色| 色婷婷综合久久久久久| 日韩国产在线看| 女尊高h男高潮呻吟| 亚洲免费成人av在线| 亚洲人高潮女人毛茸茸| 亚洲永久精品ww.7491进入| 蜜桃精品噜噜噜成人av| 精品视频在线导航| 特级西西www444人体聚色| 国产区精品区| xvideos亚洲| 欧美肥妇bbwbbw| 午夜国产精品视频| 久久人人爽人人爽人人片av高请| 日韩av综合在线| 国产日韩欧美高清免费| 日本一区二区在线免费播放| 波多野结衣大片| 麻豆免费精品视频| 69174成人网| 国产18精品乱码免费看| av综合在线播放| 欧美日韩在线精品| 91欧美在线视频| 亚洲精品一卡二卡| 激情五月宗合网| 日本在线视频一区二区| 欧美日本在线一区| 91成人在线观看喷潮蘑菇| 美女扒开腿让男人桶爽久久动漫| 亚洲裸体xxxx| 欧美做爰啪啪xxxⅹ性| 亚洲一级高清| 国产精品久久久久久av福利软件| 97精品人妻一区二区三区在线| 国产福利一区在线观看| 久久99精品久久久久久青青日本| yjizz视频网站在线播放| 亚洲精品第一国产综合野| 黄色片网址在线观看| av在线一区不卡| 日韩免费一区二区| 99久久久无码国产精品衣服| 欧美另类专区| 国产成人av在线| 精品人妻少妇AV无码专区| 久久精品免费在线观看| 亚洲中文字幕无码一区二区三区 | 高清av在线| 一区二区三区在线视频播放| 亚洲中文字幕久久精品无码喷水| 欧美激情三级| 中文字幕视频一区二区在线有码 | 日韩电影免费一区| 99久久自偷自偷国产精品不卡| 免费人成在线观看网站| 亚洲视频免费在线观看| 日韩欧美xxxx| 精品亚洲免a| 免费av在线一区| 五月婷婷丁香在线| av亚洲精华国产精华精华| 干日本少妇视频| jizz亚洲女人高潮大叫| 精品视频—区二区三区免费| 青娱乐91视频| 精品一区二区在线视频| 欧美一区1区三区3区公司 | 毛片在线能看| 亚洲成a人v欧美综合天堂 | 毛片在线免费播放| av亚洲产国偷v产偷v自拍| 红桃一区二区三区| 精品久久福利| 亚洲品质视频自拍网| 日韩精品一区三区| 国产69精品久久久久毛片 | 国产三级短视频| 亚洲欧美久久| 精品乱子伦一区二区三区| 一区二区三区伦理| 日韩一区二区在线观看视频播放| 黄色av免费播放| 蜜臀av一区二区在线观看 | 97视频精彩视频在线观看| 精品久久久久久国产91| 成人午夜精品无码区| 欧美日韩一区二区三区四区在线观看| 国产原创欧美精品| 2021av在线| 欧美三级视频在线| 懂色av蜜臀av粉嫩av永久| 奇米精品一区二区三区四区| 日韩亚洲视频| 91精品美女| 色偷偷88888欧美精品久久久| 成人黄色免费网| 国产精品免费久久久久| 艹b视频在线观看| 日韩精品欧美激情一区二区| 国产精品女主播| 三级外国片在线观看视频| 欧美日韩成人高清| 丝袜美腿小色网| 国产不卡免费视频| 真人抽搐一进一出视频| 牛牛精品成人免费视频| 国产91精品久久久久久| 国产资源在线观看| 欧美亚洲日本国产| 性生交大片免费全黄| 国产河南妇女毛片精品久久久| 奇米777四色影视在线看| 成人三级毛片| 日韩av大片在线| jyzzz在线观看视频| 欧美剧情电影在线观看完整版免费励志电影 | 久久91亚洲人成电影网站 | 一本色道久久综合亚洲精品小说| 一区两区小视频| 亚洲免费观看在线观看| 性高潮免费视频| 久久aⅴ乱码一区二区三区| 视频三区二区一区| 18国产精品| 国产成人在线一区二区| 精产国品自在线www| 亚洲大胆人体在线| 高潮无码精品色欲av午夜福利| 国产精品国产三级国产| 中文字幕视频观看| 石原莉奈在线亚洲二区| 亚洲第一综合网站| 日本久久成人网| 91九色国产社区在线观看| 岛国av在线播放| 中文字幕一精品亚洲无线一区| www.av日韩| 色av综合在线| 久久精品www人人爽人人| 久久久久亚洲蜜桃| 亚洲国产综合av| 手机精品视频在线观看| 4444亚洲人成无码网在线观看| 日韩精品丝袜美腿| 91精品久久久久久久久久入口| 福利在线免费视频| 久久夜色精品国产| 激情视频在线观看免费| 日韩亚洲欧美在线| 黄色污污视频软件| 天天影视色香欲综合网老头| 天天鲁一鲁摸一摸爽一爽| 久久综合av免费| 人妻 丝袜美腿 中文字幕| 蜜臀va亚洲va欧美va天堂| 国产l精品国产亚洲区久久| 这里只有精品在线| 色女人综合av| 亚洲欧洲色图| 国产亚洲第一区| 国产精品日韩精品在线播放| 国产精品激情av电影在线观看| 波多野一区二区| 欧美成人精品一区二区三区| 91亚洲欧美| 国产小视频国产精品| 日日躁夜夜躁白天躁晚上躁91| 制服丝袜在线91| 老熟妇一区二区三区啪啪| 五月天中文字幕一区二区| 国产午夜手机精彩视频| av爱爱亚洲一区| 久久久无码人妻精品无码| 国产在线国偷精品产拍免费yy| 男人添女人下面免费视频| 老鸭窝91久久精品色噜噜导演| 欧美男女爱爱视频| 欧美精品一区二区三区久久久竹菊| 一区二区三区在线观看www| 精品国产乱码| 秋霞久久久久久一区二区| 亚洲传媒在线| 欧洲一区二区日韩在线视频观看免费 | 极品少妇一区二区| 污污的视频免费观看| 久久国产精品免费| 亚洲精品午夜在线观看| 日韩av一级片| 国产小视频精品| 久久精品理论片| 午夜免费福利视频在线观看| 麻豆精品国产传媒mv男同| 性欧美1819| 国产一区二区视频在线播放| 在线免费看污网站| 国产黑丝在线一区二区三区| 免费黄视频在线观看| 丁香婷婷综合色啪| 亚洲一区二区在线免费| www国产成人| 精品人妻中文无码av在线| 国产精品另类一区| 国产极品国产极品| 亚洲激情图片小说视频| 国产在线拍揄自揄拍| 婷婷丁香久久五月婷婷| 精品人妻一区二区色欲产成人| 色久优优欧美色久优优| 最近中文字幕av| 在线综合视频播放| 亚洲大尺度视频| 精品呦交小u女在线| 浮生影视网在线观看免费| 日韩在线观看你懂的| 少女频道在线观看免费播放电视剧| 欧美精品做受xxx性少妇| 激情国产在线| 国产精品三级网站| 中文字幕亚洲在线观看| 蜜桃91精品入口| 99精品在线免费在线观看| 国产一区二区四区| 天堂久久一区二区三区| 国产福利精品一区二区三区| 成人国产亚洲欧美成人综合网 | 奇米777在线视频| 成人av影院在线| 久久久久无码精品国产sm果冻| **欧美大码日韩| 日韩成人一区二区三区| 欧洲国内综合视频| www.热久久| 亚洲热线99精品视频| 羞羞网站在线免费观看| 青青草成人在线| 国产精品成人3p一区二区三区| 精品日本一区二区三区在线观看| 欧美成免费一区二区视频| 免费一级特黄毛片| 六月丁香婷婷色狠狠久久| 黑人玩弄人妻一区二区三区| 国产日韩影视精品| 久久视频免费看| 欧美中文字幕亚洲一区二区va在线| 亚洲免费成人在线| 少妇av一区二区三区| 黄视频网站在线观看| 114国产精品久久免费观看| 国产欧美日韩在线一区二区| 男女私大尺度视频| 免费在线观看av的网站| 欧美性做爰猛烈叫床潮| 秋霞网一区二区| 久久精品视频va| 欧美特大特白屁股xxxx| 国产精品日本一区二区| 欧美mv日韩| 免费大片在线观看| kk眼镜猥琐国模调教系列一区二区| 欧美日韩高清在线观看| 无遮挡爽大片在线观看视频 | 另类尿喷潮videofree| 老司机av福利| 日本视频免费一区| 国产成人av一区二区三区不卡| 亚洲国产成人高清精品| 99久久精品国产色欲| 色七七影院综合| 欧美色片在线观看| 久久久影院一区二区三区| 海角社区69精品视频| 四虎永久免费网站| 在线观看国产亚洲| 欧美一区午夜精品| av天在线观看| 国产成人啪精品视频免费网| 青青视频一区二区| www..com日韩| 成人午夜在线播放| 久久综合久久鬼| 欧美xxxx在线观看| 丝袜综合欧美| 成人片在线免费看| 激情视频一区| 老熟女高潮一区二区三区| 亚洲主播在线播放| 丰满肉肉bbwwbbww| 国内精品久久久久久中文字幕| 一级毛片精品毛片| 青青青在线观看视频| 成人国产电影网| 久久久久久久极品| 亚洲美女性视频| 日韩av超清在线观看| 亚洲欧美在线网| 精品在线你懂的| xxxx日本少妇| 欧美一区二区三区免费观看视频 | 国产97在线视频| 日韩成人av在线资源| 欧美一级视频免费看| 91丨九色丨黑人外教| 久久午夜免费视频| 亚洲天堂2020| 国产黄色精品| 一区二区三区国产福利| 久久www免费人成看片高清| 小早川怜子一区二区的演员表| 91精品国产综合久久精品| 欧美人与性动交α欧美精品济南到 | 欧美精品99久久久| 精品乱码亚洲一区二区不卡| 色在线中文字幕| 日本在线播放不卡| 狠狠网亚洲精品| 鲁鲁视频www一区二区| 亚洲 美腿 欧美 偷拍| 欧美精品在线观看91| 哺乳挤奶一区二区三区免费看| 97超碰国产精品| 2欧美一区二区三区在线观看视频 337p粉嫩大胆噜噜噜噜噜91av | 青青久久av北条麻妃海外网| 国产探花一区| 天天操天天摸天天爽| 亚洲免费观看高清完整版在线观看熊| jizz中国女人| 亚洲 日韩 国产第一| 精品美女久久| 欧美日韩理论片| 精品露脸国产偷人在视频| 国产区av在线| 99国精产品一二二线| 亚洲深夜影院| 国产又粗又硬又长又爽| 精品国产一区二区三区忘忧草 | 亚洲激情图片一区| 精品久久久久一区二区三区| 国产精品视频成人| 伊人色**天天综合婷婷| 玖玖爱在线精品视频| 色老综合老女人久久久| 大桥未久在线播放| 日韩国产在线一区|