原文地址:Deep dive into Live Edit for Jetpack Compose UI
原文作者: Alan Leung, Staff Software Engineer,Fabien Sanglard, Senior Software Engineer, Juan Sebastian Oviedo, Senior Product Manager

近距离了解 Android Studio 团队怎么构建 Live Edit;该功用可在代码更改时继续更新运转中的运用程序,然后加快 Compose 的开发进程。

什么是实时编辑(Live Edit),它怎么协助我?

Live Edit 引入了一种编辑运用程序 Jetpack Compose UI 的新办法,即经过立行将代码更改部署到物理设备或模拟器上正在运转的运用程序。这意味着您可以对运用程序的 UI 进行更改,并立即看到它们对正在运转的运用程序的影响,然后使您可以更快地进行迭代并进步开发效率。Live Edit 最近现已过 Android Studio Giraffe 发布到稳定频道,而且可以在编辑器设置中启用。Plex 和 Pocket Casts 等开发人员现已在运用 Live Edit,它加快了 Compose UI 的开发流程。它还协助他们从 XML 视图迁移到 Compose。

[译] 深入探究 Jetpack Compose UI的实时编辑(Live Edit)
Android Studio Hedgehog 上的 Live Edit

什么时候我应该运用 Live Edit ?

Live Edit 是与 Compose Preview 和 Apply Changes 不同的功用。这些功用以不同的办法供给价值:

功用 描述 何时运用?
Live Edit [仅限 Kotlin,支撑实时重组] 对您的 Compose 运用程序的用户界面进行更改,并立即检查其对模拟器或物理设备上正在运转的运用程序的影响。 快速检查 UX 元素更新(如 modifier 更新和动画)对运用程序运转时整体运用体会的影响。
Compose Preview [仅 Compose ]在 Android Studio 的 “Design” 选项卡中将 Compose 元素可视化,并在您修正代码时看到它们主动改写。 以一种或多种不同的装备和状况(如暗色主题、本地化和字体比例)预览单个 Compose 元素。
Apply Changes 将代码和资源更新部署到运转中的运用程序,而无需重启该运用程序,在某些情况下,也无需重启当时 activity 。 在非Compose运用程序中更新代码和资源,无需从头部署到模拟器或物理设备中。

它的完结原理 ?

在高层次上,Live Edit 会履行以下操作:

  1. 检测源代码更改
  2. 编译更新的类
  3. 将编译好的新类推送到设备上
  4. 为每个类办法字节码添加钩子,以重定向调用到新的字节码。
  5. 修正运用程序的 classpath ,以确保更改在运用程序从头启动时更改依然存在。

[译] 深入探究 Jetpack Compose UI的实时编辑(Live Edit)
Live Edit architecture

Keystroke detection 击键检测

这个进程是经过 Intellij IDEA 的 Program Structure Interface (PSI) 树来处理的,监听器使得 Live Edit 可以检测到开发者在Android Studio编辑器中进行更改的时间。

编译

从根本上来说,Live Edit 依然依赖 Kotlin compiler 为每个增量更改生成代码。

咱们的方针是创立一个体系,从最终一次按键到设备上产生重组之间的延迟小于 250 毫秒。传统意义上的增量构建或调用外部编译器无法满意咱们的功用要求。相反,Live Edit 利用了 Android Studio 与 Kotlin compiler 的严密集成。

在最高层面上,Kotlin编译器的编译可以分为两个阶段。

  • 剖析(Analysis)
  • 代码生成 (Code generation)

作为第一步履行的剖析并非完全限定于构建进程。事实上,同样的进程经常在构建体系之外作为 IDE 的一部分完结。从根本语法检查到主动完结主张,IDE 不断履行相同的剖析(上图的进程 1)并缓存成果,以便为开发人员供给 Kotlin 和 Compose 特定的功用。咱们的试验标明,大部分编译时间都花在构建进程中的剖析阶段。Live Edit 运用这些信息来调用 Compose 编译器。这使得开发人员运用的典型笔记本电脑可以在 200 毫秒内完结编译。Live Edit 进一步优化了代码生成进程,并仅专心于生成更新运用程序所需的代码。

成果是一个一般的 .class 文件(不是 .dex 文件),该文件被传递到管道中的下一步,即 desugaring

怎么脱糖(desugar)

当构建体系处理 Android 运用程序源代码时,通常会在编译后对其进行 “desugared” 处理。这一转换进程答应运用程序在一组没有语法糖支撑和最新 API 功用的 Android 版别上运转。这样,开发人员就可以在运用程序中运用新的 API,一起还能让运转旧版别 Android 的设备运用这些 API。

有两种类型的脱糖,分别称为言语脱糖(language desugaring)和库脱糖(library desugaring)。这两种转换都由R8履行。为了确保注入的字节码与设备上当时运转的字节码共同,Live Edit 有必要确保每个类文件的脱糖办法与构建体系选用的脱糖办法保持兼容。

言语脱糖(Language desugaring):

这种字节码重写旨在为低版别的API设备供给更新的言语特性。其方针是支撑诸如默许接口办法、lambda 表达式、办法引证等言语特性,以便支撑最低API等级。这个值是经过 R8 在 .apk 文件的 DEX 文件中留下的标记提取出来的。

API脱糖(API desugaring):

也叫做库脱糖,它旨在支撑 JAVA SDK 中的办法和类。这是经过一个 JSON 文件进行装备的。除此之外,办法调用点被重写为位于desugar library(该库也嵌入在运用程序中的 DEX 文件中) 中的方针函数。为了履行这个进程,Gradle 与 Live Edit 合作,供给用于脱糖需要的 JSON 文件。

办法跳板(Function trampoline)

为了方便对运转中的运用程序进行快速的 “per-key-stroke” 速度更新,咱们决定不运用 Android Runtime (ART) 的 JVMTI codeswap 才能来处理每一个编辑操作。相反,JVMTI 只被用于一次代码交换,将办法跳板安装到虚拟机内行将修正的类的子集中。咱们运用了一个被称为 “Primer” 的东西(上图进程3),将办法的调用重定向到一个专门的解说器。当运用程序一段时间内没有接收到更新时,Live Edit 将运用传统的 DEX 代码替换代码,以进步 ART 的功用优势。这样一来,开发者就可以节省时间,随着代码的更改,即时更新正在运转的运用程序。

[译] 深入探究 Jetpack Compose UI的实时编辑(Live Edit)
办法跳板处理 Function trampoline process

代码怎么被解说

Live Edit 可以动态编译代码。生成的 .class 文件会被推送、重定向(如之前所述),然后在设备上进行解说。这个解说进程是由 LiveEditInterpreter履行的。这个解说器不是在 ART 内部树立的完好虚拟机,而是基于 ASM Frame 构建的帧解说器( Frame interpreter )。ASM Frame 处理低等级的逻辑,比方仓库/本地变量的推送/加载,但需要一个解说器来实际履行操作码。这便是 OpcodeInterpreter 的效果。

[译] 深入探究 Jetpack Compose UI的实时编辑(Live Edit)
Live Edit 的解说流程

Live Edit Interpreter 是一个简单的循环,它驱动 ASM/Interpreter 操作码的解说履行。

一些 JVM 指令无法运用纯 Java 解说器完结(特别是 invokeSpecialmonitorEnter/Exit 指令存在问题)。关于这些指令,Live Edit 运用 JNI 进行解说。

处理 lambda

Lambda 表达式的处理办法有所不同,因为 lambda 捕获的更改或许会导致 VM 类产生更改,而这些更改在许多办法签名中都不同。因此,新的与 lambda 相关的更新会作为新类发送到正在运转的设备上,而不是像前面一节所述那样从头界说任何已加载的现有类。

重组怎么进行?

开发者期望有一种无缝的、无障碍的新办法来编写 Android 运用程序。Live Edit 的要害体会之一是在开发者继续编写代码的一起看到运用程序的更新,而无需明确地按下按钮触发从头运转。咱们需要一个 UI 结构,可以监听运用程序中的模型更改并相应地履行最优的重绘。幸运的是,Jetpack Compose 完美地合适这项任务。经过 Live Edit,咱们为呼应式编程范式增加了另一个维度,即结构还观察函数代码的更改。

为了方便监视代码修正,Jetpack Compose 编译器向 Android Studio 供给了将函数元素映射到一组重组组合的映射。附加的 JVMTI 代理以异步办法使已更改函数的 Compose 状况无效,而且 Compose Runtime 对无效的 Composables 履行从头组合。

重组期间的过错怎么处理?

[译] 深入探究 Jetpack Compose UI的实时编辑(Live Edit)
Live Edit 处理运转时过错

虽然继续更新运用程序的概念十分令人兴奋,但咱们的实地研讨标明,有时当开发者编写代码时,程序或许处于不完好的状况,更新和从头履行某些函数或许会导致不良成果。除了简直接连产生更新的主动形式之外,咱们还为期望对检测到新代码后何时更新运用程序进行更多控制的开发人员引入了两种手动形式。

即使如此,咱们仍要确保由于履行不完好的函数而导致的常见问题不会导致运用程序提前终止。Live Edit 会检测循环的退出条件仍在编写的情况,以避免程序内呈现无限循环。此外,如果 Live Edit 更新触发重组并导致抛出运转时反常,则 Compose Runtime 将捕获此类反常并运用最终一次已知的杰出状况进行重组。

考虑以下代码片段:

var x = y / 10

假定开发者想经过删去字符 1 并在后边刺进字符 5 来将 10 更改为 50。Android Studio 或许会在刺进 5 之前更新运用程序,然后创立一个除以零的 ArithmeticException。可是,经过上述的的对过错处理功用,运用程序将简单地康复为 y / 10,直到在编辑器中进跋涉一步更新。

行将产生什么?

Android Studio 团队信任 Live Edit 将以活跃的办法改动 UI 代码的编写办法,并致力于不断改进 Live Edit 的开发体会。咱们正在努力扩展开发者可以履行的编辑类型。此外,未来版别的 Live Edit 将消除在某些情况下需要使整个运用程序无效的需要。

此外,PSI 事情检测存在限制,例如当用户编辑 import 句子时。为解决这个问题,未来版别的 Live Edit 将依赖于 .class 比较来检测更改。最终,完好的耐久化功用目前尚不可用。未来版别的 Live Edit 将答应在 Android Studio 之外从头启动运用程序并保留 Live Edit 更改。

开始运用 Live Edit

Live Edit 现已可以在出产环境中运用,咱们期望它可以极大地改进您在 Android 上开发的体会,尤其是在 UI-heavy 迭代方面。咱们十分乐意听取您更多关于有趣的运用事例、最佳实践、过错报告和主张。

如果您在阅读中发现有翻译不精确的当地,请随时联系我更改。