@Preview驱动 Jetpack Compose 开发

必要性是发明之母.

柏拉图

每个想法都源于需求, 这次也不例外. 在 Whatnot 的日常功能开发过程中, 我一直在努力跟上业务发展的步伐. 我必须在一周内实现一个相当庞大的功能, 确保一切按预期运行. 但怎么做呢? 为了提供高质量的软件, 我们应该少走哪些弯路? 让我一步一步来解释.

首先, 让我们把重点放在我认为阻碍编码速度的事情上.

  • 我真丢人啊! 从业务角度和设计角度来看, 在编写单元测试的同时, 还要实现每两小时就会变化一次的边缘功能是相当痛苦的.
  • 手动测试复杂的用户路径令人沮丧, 而且会破坏专注力.
  • 应用的构建时间. 复杂的代码库会降低开发速度. 我们都经历过这种痛苦!

🏃 跳过单元测试!

跳过单元测试会产生一个不好的副作用, 那就是无法单独执行和测试代码. 每分钟都在设备上构建应用非常耗时, 我们就是这样耗费了大量的开发周期. 另一个隐患是在不引入新错误的情况下修复错误. 如果没有可靠的回归套件, 这几乎是不可能的.

我决定在功能开发期间可以不进行单元测试, 在产品发布后再编写单元测试. 与此同时, 我还付出额外的努力, 确保我编写的代码是可测试的, 干净的. 这并不是一个巨大的挑战, 因为我们的架构构建器已经非常成熟和强大. 你猜怎么着? 跳过测试驱动开发为我节省了大量时间! 我能够快速编写代码, 并毫不费力地调整实现.

不幸的是, 在设备上进行测试破坏了我的注意力, 我知道我必须为此做点什么. 让我们试试!

🔗‍💥 在设备上测试

对于 Android 工程师来说, 快速的 Android 模拟器, 增量编译和构建缓存无疑是最好的东西之一. 每隔几分钟运行一次应用并不是一件很痛苦的事, 但如果我们需要测试特定的验证场景, 错误状态或空路径呢? 这些复杂的用户路径可能会耗费我们一些时间和精力. 正如我之前提到的, 单元测试可以让我们隔离运行代码, 设置初始状态并获得快速反馈, 从而帮助我们解决这个问题. 我们如何才能将这种方法应用到根本不存在测试的世界中呢?

为了回答这个问题, 请允许我简要介绍一下我们的 Whatnot Android 技术栈. 在Whatnot, 我们正在构建实时购物和市场, 在这里您可以购买, 出售和发现您喜爱的产品. 除了实时流媒体, 我们还有大量的卖家和买家功能, 以及丰富的原生用户界面体验. 我们在早期阶段就采用了 Jetpack Compose, 这一决定不仅缩短了开发周期, 还让开发人员感到愉悦和满意.

Jetpack Compose 是现代安卓用户界面工具包, 可以大大加快开发速度. 所生成的代码不仅更简单, 而且更优雅, 更简洁. 我们还使用 Jetpack ViewModel 为我们的可组合用户界面提供正确的状态. 简要说明: MVI 上线. ViewModel 只不过是一个容器, 它粘合了几个函数, 这些函数根据网络结果还原状态, 并将其推送到视图层.

🔁⚒️ 修复快速反馈回路

现在, 当你知道我们使用了哪些工具后, 我可以开始解释我是如何想出一个解决方案来修复损坏的反馈环路的.

我的目标是建立一个简便的解决方案, 以便在运行用户界面的同时, 孤立地运行模型层. 此外, 我还希望它快速, 可靠并具有预测性. 我想到了几个问题:

  1. 如何隔离运行Compose代码?
  2. 如何隔离运行模型逻辑?
  3. 如何构建一组预定义状态, 用于测试回归?

首先, 隔离运行 @Composable 函数非常简单. Jetpack Compose 附带了一个额外的工具工件, 可以直接在 Android Studio Preview 中渲染它.

scss 复制代码
debugImplementation("androidx.compose.ui:ui-tooling:VERSION")
implementation("androidx.compose.ui:ui-tooling-preview:VERSION")

这对于创建一组变体并以简单快捷的方式对其进行测试非常方便. 下面是在 Whatnot 设计系统中使用 @Preview 可视化所有二级按钮状态的示例.

下一个难题有点难. 我们如何使用 @Preview 来单独运行整个屏幕甚至整个用户流程? 用 Compose 编写的常规屏幕比按钮有更复杂的功能参数, 但这是个问题吗? 这是一个挑战!

让我们从定义屏幕的公共 API 开始.

正如你所看到的, 通过提供函数参数, 我们可以在 @Preview 中将其作为普通 Composable 运行.

ScreenViewModel 是使用假用例手工创建的. 通过使用另一个 Compose 工具, 我们可以做得更好. @PreviewParameter!

这很好, 不是吗? 通过使用 PreviewParameterProvider 和 @PreviewParameter, 我们可以定义任意多的案例. 所有案例都将在 Android Studio 预览版中自动呈现. 它们采用与 JUnit 测试参数相同的编码方法.

到目前为止, 我们取得了哪些成果? 我们知道了如何单独渲染屏幕及其模型逻辑. 这很好, 但这足以解决反馈环路的问题吗? 还不够, 因为我们还不知道如何使用 @Preview 来运行 而不仅仅是渲染复杂的用户路径.

为了简化复杂的用户路径, 想象一下, 我们有一个用户流程, 该流程会显示一个发货配置文件列表, 并提供添加, 更新和删除每个配置文件的功能. 除此之外, 每个屏幕都应适当处理空, 错误和数据状态. 我们还需要一些高级表单验证, 以确保用户知道该做什么. 我们的 Whatnot 应用中就有这样的流程, 让我们以它为例.

Whatnot 发货配置文件用户流程

正如您所看到的, 视频只展示了流程的一部分, 因为它仅从 "配置文件 "选项卡开始. 实际上, 测试每个用例都会更加复杂, 因为我们需要登录, 进入正确的界面, 并确保所有功能标志和配置都设置正确. 不过不要害怕. 我们可以使用 @Preview 独立运行流程!

说到细节, 值得一提的是我们使用了 Compose Navigation, 它只不过是一个 Jetpack 导航组件. 它让生活变得更轻松, 并带有一些方便的动画和工具.

运输配置文件流程的入口看起来是这样的:

哦, 天哪, 乍一看还挺吓人的, 但让我从更高层次的角度来解释一下这里发生了什么.

  1. shippingProfileFlow 是一个扩展函数, 可以轻松连接到任何导航图. 这使得流程可以在整个代码库中重复使用.
  2. shippingProfileFlow 函数定义了六个不同的导航目的地, 如列表, 创建, 编辑, 两种错误类型以及一些成本优化信息.
  3. 最重要的是最后三个参数: viewModelStoreOwnerProvider , shippingProfilesViewModelProvider , shippingProfileViewModelProvider. 它们带来了实际的 "魔法", 让我们可以注入假的模型提供程序, 并隔离运行代码.
  4. 默认情况下, shippingProfilesViewModelProvider 具有真正的实现, 可根据 LocalViewModelStoreOwner.current 注入正确的对象实例.
  5. 默认情况下, shippingProfileViewModelProvider 的实际实现是根据作为参数传递的viewModelStoreOwnerProvider注入一个正确的对象实例.

这种技术与众所周知的依赖注入没什么不同. 有了这些, 我们就可以单独添加 @Preview 代码和RENDER流程了.

首先, 定义 @PreviewParameter(s).

然后添加 @Preview 函数.

这段代码中最吵闹的部分是用于创建 modalBottomSheetLayout 的辅助函数, 但我决定不介绍它, 因为它在这里没有任何实际价值. 同样的规则也适用于虚假替换.

最后! 我们可以在 Android Studio 预览版中渲染我们的流程了.

成功了! 那么在模拟器上运行呢?

正如你所看到的, 流程在隔离状态下运行, 我们只需不到一秒钟的时间就能玩转它们. 我能够将"静态"的 @Preview 转变为完全成熟的 @Preview 驱动开发工具. 它加快了代码编写速度, 只需在数据提供程序中编写几行代码, 就能伪造出不同的复杂场景. 除此之外, @Preview 案例还是很好的文档和手动回归集.

🤓 主要收获

我知道, 这可能需要消化很多东西, 但如果你已经在 Jetpack ViewModel 中使用了 Compose, 那么在你的代码库中应用同样的策略应该不难.

再回到阻碍编码速度的地方.

  1. 跳过编写单元测试并不是我推荐的做法, 但这样可以节省时间. 事实上, 时间不是省下来的, 而是从未来借来的! 发布后, 我编写了完整的单元测试套件, 以加快回归速度. 这花了我一天时间, 因为业务逻辑和用户体验都已经解决了.
  2. 使用 @Preview 运行复杂的用户路径改变了我的游戏规则! 超级易于维护, 可靠且快速!
    1. 增量构建时间不到两秒, 通过 @PreviewParameter 进行伪造简单明了.

总而言之, 如果你还没有使用Compose @Preview 工具, 我非常鼓励你开始使用它. 在 Whatnot, 我们正在实施Compose设计系统, 我无法想象没有交互式 @Preview 的情况.

相关推荐
GEEKVIP2 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
model20054 小时前
android + tflite 分类APP开发-2
android·分类·tflite
彭于晏6894 小时前
Android广播
android·java·开发语言
与衫5 小时前
掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系
android·javascript·sql
500了11 小时前
Kotlin基本知识
android·开发语言·kotlin
人工智能的苟富贵12 小时前
Android Debug Bridge(ADB)完全指南
android·adb
小雨cc5566ru17 小时前
uniapp+Android面向网络学习的时间管理工具软件 微信小程序
android·微信小程序·uni-app
bianshaopeng18 小时前
android 原生加载pdf
android·pdf
hhzz18 小时前
Linux Shell编程快速入门以及案例(Linux一键批量启动、停止、重启Jar包Shell脚本)
android·linux·jar
火红的小辣椒19 小时前
XSS基础
android·web安全