精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

日本美女高清在线观看免费| 日韩人妻精品中文字幕| 精品一区二区三区在线观看视频| 樱桃国产成人精品视频| 国语精品中文字幕| 中文字幕第315页| 欧美午夜一区二区福利视频| 亚洲精品久久久久久下一站| 69久久久久久| 17videosex性欧美| 国产精品久久综合| 国产亚洲精品自在久久| 夜夜嗨aⅴ一区二区三区| 亚洲一级二级| 最新国产精品拍自在线播放| 看全色黄大色黄女片18| 美女久久久久久| 五月婷婷另类国产| 国产a级片免费看| 欧美挠脚心网站| 国产一区二区免费视频| 日产日韩在线亚洲欧美| 成人免费看片98| 日本一区二区免费高清| 亚洲国产精品专区久久| 91aaa精品| 91tv亚洲精品香蕉国产一区| 亚洲成av人影院在线观看网| 中文字幕一区二区中文字幕| 欧美视频综合| caoporn国产一区二区| 成人av资源在线播放| 日本a级c片免费看三区| 亚洲国产黄色| 欧美精品在线极品| 多男操一女视频| 国产日产精品一区二区三区四区的观看方式| 日韩三级精品电影久久久| 尤蜜粉嫩av国产一区二区三区| 99热99re6国产在线播放| 综合中文字幕亚洲| 亚洲国产精品综合| 粉嫩一区二区三区国产精品| 91香蕉视频mp4| 国产欧美日韩综合一区在线观看 | 婷婷久久国产对白刺激五月99| 日韩精品亚洲精品| 中文字幕人妻一区| 大伊香蕉精品在线品播放| 91精品国产综合久久久久久漫画 | 色午夜这里只有精品| 熟女俱乐部一区二区| 国产精品15p| 亚洲韩国日本中文字幕| 伊人网综合视频| 精品视频高潮| 日韩精品视频在线| a级大片在线观看| 精品毛片免费观看| 北条麻妃久久精品| 丰满少妇被猛烈进入一区二区| 天天综合亚洲| 欧美另类极品videosbestfree| 欧美色图亚洲视频| 亚洲第一精品影视| 91精品国产乱码久久久久久久久| 中文字幕在线观看视频网站| 麻豆精品网站| 国产日产欧美精品| 国产a级免费视频| 成人综合在线视频| 欧美日韩电影一区二区| av午夜在线| 亚洲欧美电影院| 成人免费观看cn| 欧美momandson| 欧美人与禽zozo性伦| 杨幂一区二区国产精品| 久久夜色精品国产噜噜av小说| 精品无码久久久久久国产| 91l九色lporny| 性欧美欧美巨大69| 97在线观看视频国产| 69视频免费看| 国产福利一区二区三区视频 | 欧美成人激情| 欧美激情亚洲自拍| 国产伦精品一区二区三区视频我| 美腿丝袜亚洲一区| 国产免费一区| 69av亚洲| 午夜成人免费电影| 九九九九九九九九| 琪琪久久久久日韩精品| 日韩最新在线视频| 国产成人精品一区二三区| 久久精品72免费观看| 国产一区二区久久久| 91大神在线网站| 五月天亚洲婷婷| 免费av不卡在线| 网友自拍一区| 欧美日韩国产成人在线| 亚洲高清视频免费观看| 成人国产亚洲欧美成人综合网| 午夜精品区一区二区三| 91九色porn在线资源| 欧美日韩激情在线| 无码人妻aⅴ一区二区三区| 天天操夜夜操国产精品| 欧美诱惑福利视频| 精品久久无码中文字幕| 欧美男男gaytwinkfreevideos| 中文字幕亚洲无线码a| 久久久久无码国产精品不卡| 青青草91视频| 久久久久久国产精品一区 | 亚州综合一区| 欧美人在线观看| 伊人网视频在线| 国产亚洲欧美日韩在线一区| 91丨porny丨探花| 精品中文在线| 最近2019免费中文字幕视频三| 天海翼一区二区| 国产精品88av| 一本二本三本亚洲码| 91久久久久久白丝白浆欲热蜜臀| 日韩av最新在线| 香蕉视频一区二区| 国产v日产∨综合v精品视频| 一区二区三区四区五区视频| 丁香六月综合| 精品香蕉在线观看视频一| 国产无套内射又大又猛又粗又爽 | 91免费观看| 毛片在线视频| 欧美日本精品一区二区三区| 少妇精品无码一区二区免费视频| 亚洲免费综合| 精品一区二区日本| 黄色18在线观看| 亚洲精美色品网站| 久久网免费视频| 成人中文字幕合集| www污在线观看| 成人盗摄视频| 97视频人免费观看| 午夜小视频免费| 欧美日韩午夜视频在线观看| 亚洲av网址在线| 亚洲一区二区成人| 欧日韩一区二区三区| 男女羞羞在线观看| 亚洲免费电影在线观看| 色老头在线视频| 国产精品天干天干在线综合| 最新天堂中文在线| 亚洲精品久久久| 99久久久精品免费观看国产| 欧美人与禽猛交乱配| 精品国产91乱码一区二区三区| 久热精品在线观看| 久久综合久久综合九色| 91淫黄看大片| 99精品在线免费在线观看| 91精品视频在线播放| 污污网站在线观看| 日韩国产欧美精品在线| 懂色av中文字幕| 中文字幕一区二区三区av| 又色又爽又黄18网站| 夜夜嗨av一区二区三区网站四季av| 久久精品丝袜高跟鞋| 日韩不卡在线| 久久成人综合视频| 天堂在线免费av| 欧美日韩国产乱码电影| 欧美黄片一区二区三区| 91视视频在线直接观看在线看网页在线看| 国产一级不卡毛片| 一区二区三区在线| 精品在线观看一区二区| 国产91精品在线| 欧美激情亚洲激情| 大地资源中文在线观看免费版| 在线播放亚洲一区| 日韩免费一级片| 国产精品三级视频| 97人妻精品一区二区三区免费| 青青国产91久久久久久 | 久久国产成人| 日韩不卡一二区| 伊甸园亚洲一区| 亚洲综合小说区| 日韩三区免费| 久久久伊人欧美| 秋霞午夜理伦电影在线观看| 亚洲国产精品中文| 99久久夜色精品国产亚洲| 欧美日韩一区二区免费在线观看| 日本不卡一区视频| 91丨porny丨首页| 国产大学生av| 麻豆一区二区在线| 精品一区二区中文字幕| 欧美/亚洲一区| 亚洲国产一区二区三区在线| 国产精品超碰| 91日本视频在线| 日韩网站中文字幕| 欧美一级高清免费播放| 免费在线观看的电影网站| 日韩亚洲在线观看| 黄色电影免费在线看| 亚洲电影免费观看高清完整版在线观看| 在线视频1卡二卡三卡| 粉嫩老牛aⅴ一区二区三区| 青青草在线观看视频| 国产精品久线观看视频| 成人片黄网站色大片免费毛片| 国产91精品久久久久久久网曝门| 一个色综合久久| 蜜臂av日日欢夜夜爽一区| 热久久精品国产| 亚洲免费婷婷| 欧美韩国日本在线| 9国产精品视频| 国产a级片网站| 亚洲一级二级| av高清在线免费观看| 国产综合网站| 日韩a级黄色片| 欧美大片专区| 特大黑人娇小亚洲女mp4| 91视频久久| 亚洲一区三区电影在线观看| 狠狠做深爱婷婷综合一区| 欧美精品七区| 国产一区二区在线| 日本一区精品| 欧美日韩性在线观看| 日韩精品国内| 日韩av在线播放网址| 一区二区视频国产| 欧美一区二区| 日韩伦理在线免费观看| 影音先锋久久| 欧美亚洲国产成人| 亚洲欧美日本视频在线观看| 黄色一级大片在线观看| 日韩精品免费专区| 黄色三级视频在线| 精品一区二区久久久| 一区二区三区国产好的精华液| 国产一区二三区| 第一页在线视频| 99久免费精品视频在线观看| 伊人网在线视频观看| 国产欧美日韩视频在线观看| 少妇视频在线播放| 亚洲精品视频自拍| 久久精品国产亚洲av无码娇色| 五月开心婷婷久久| 欧美超碰在线观看| 欧美日韩电影一区| 超碰人人人人人人| 日韩av网址在线| 国产三级视频在线| 久久久久999| 成人ssswww在线播放| 日韩免费不卡av| 宅男噜噜噜66国产精品免费| 不卡一卡2卡3卡4卡精品在| 国内露脸中年夫妇交换精品| 欧美大香线蕉线伊人久久| 成人激情开心网| 日韩欧美视频免费在线观看| 国产精品美女久久久浪潮软件| 成人黄色一区二区| 国产乱对白刺激视频不卡| 成人网站免费观看| 国产精品久久久久影院色老大 | 91嫩草国产在线观看| 久久影院资源站| 综合视频免费看| 一本色道88久久加勒比精品| 手机视频在线观看| 国产jizzjizz一区二区| 69精品无码成人久久久久久| 一区二区在线观看免费| 日韩人妻精品中文字幕| 日韩一区二区三区高清免费看看| 飘雪影视在线观看免费观看 | 日韩影片在线播放| 红桃视频国产精品| 久久久精品麻豆| 99久久99久久免费精品蜜臀| 欧美视频一区二区在线| 精品毛片三在线观看| 国产成人久久精品77777综合 | 日韩人妻无码精品综合区| 亚洲乱码一区二区三区在线观看| 精品不卡一区二区| 欧美成人精品高清在线播放| 幼a在线观看| 人九九综合九九宗合| 综合成人在线| 在线视频不卡一区二区三区| 性久久久久久| 无码人妻精品一区二区三区99不卡| 国产精品国产三级国产普通话99 | 欧美老人xxxx18| 偷拍精品一区二区三区| 不卡av在线网站| 国产精品久久久久久吹潮| 免费国产一区| 亚洲精品激情| 91精品人妻一区二区三区四区| 国产精品国产三级国产普通话三级| www.色国产| 亚洲欧美日韩精品久久奇米色影视| 超碰中文在线| 成人9ⅰ免费影视网站| 一区二区日韩欧美| 一级黄色特级片| 亚洲国产精品av| 亚洲国产精品无码久久久| 日韩av网站在线| 瑟瑟视频在线看| 国产美女精品在线观看| 欧美激情四色| 久久久久久久久久久影视| 亚洲啪啪综合av一区二区三区| 奴色虐av一区二区三区| 亚洲欧美在线一区| 免费观看亚洲| 欧美日韩在线观看一区二区三区| 国产精品夜夜夜| 无套内谢大学处破女www小说| 亚洲va国产天堂va久久en| 欧美一级一区二区三区| 国模精品一区二区三区色天香| 福利在线一区| 欧美啪啪免费视频| 99精品视频在线免费观看| 免费观看一区二区三区毛片 | 日本三级视频在线观看| 国产精品欧美日韩久久| 久久国产影院| 91在线第一页| 亚洲一区二区四区蜜桃| 乱色精品无码一区二区国产盗| 久久久这里只有精品视频| 欧美影院天天5g天天爽| www.亚洲天堂网| 久久久资源网| 欧美精品videos性欧美| 国产成人tv| 日韩女优在线播放| 大色综合视频网站在线播放| 一路向西2在线观看| 亚洲欧美在线视频| 亚洲a视频在线| 91av在线免费观看视频| 国产精品一区二区99| 伊人影院综合在线| 一级特黄大欧美久久久| 免费看黄网站在线观看| 日本免费在线精品| 97精品国产福利一区二区三区| 美女被艹视频网站| 午夜欧美视频在线观看| 免费在线视频一级不卡| 国产精品视频在线观看| 综合在线一区| 欧美xxxxx精品| 欧美性欧美巨大黑白大战| 97caopor国产在线视频| 久久久久久99| 国产在线观看一区二区| 国产午夜精品一区二区理论影院| 亚洲欧美日韩图片| 成年永久一区二区三区免费视频| www.成年人视频| 国产精品三级电影| 欧美一区二区三区激情| 国产精品麻豆va在线播放| 欧美日韩精品一本二本三本 | 精品国产无码一区二区三区| 久久久久中文字幕2018| 欧美日韩水蜜桃| av漫画在线观看| 精品视频免费看| caoporn-草棚在线视频最| 亚洲乱码一区二区三区| 99视频超级精品| 国产熟女一区二区三区四区| 琪琪亚洲精品午夜在线| 欧美日韩亚洲一区三区|