结合FirstComposeApp重构LoginActivity实战

2026-03-31 21:36 结合FirstComposeApp重构LoginActivity实战已关闭评论

010 结合 FirstComposeApp 重构 LoginActivity 实战

今天我想和你分享一个我最近在做的实战项目:重构一个传统的 Android 登录页面,把它变成一个更符合 Compose 风格的现代表单页。这个项目就在我的本地目录 D:\dazhao\androidStudio\FirstComposeApp 里。

我的目标很明确,不是简单地“再写一个登录页”,而是想通过重构 LoginActivity.kt 这个具体的例子,来掌握 Compose 中最常见、也最实用的一类页面——表单页的构建模式。这对我后续开发其他类似页面帮助巨大。

1. 这次重构,我已经完成了什么

在动手之前,我先梳理了现状。原来的 LoginActivity.kt 是一个典型的传统写法。经过这次重构,我已经成功完成了以下升级:

  • 结构拆分:把原先 Activity 内部直接写 UI 的方式,清晰地拆成了 LoginRoute()LoginScreen(...) 两层。
  • 状态提升:采用了 Compose 推荐的状态提升写法,让数据流向更清晰。
  • 基础校验:为用户名和密码增加了非空等基础校验逻辑
  • 智能按钮:登录按钮现在只有在表单内容合法时才可点击,体验更好。
  • 加载状态:点击登录时,按钮会显示一个简单的 loading 状态,防止重复提交。
  • 独立预览:Preview 现在可以预览无状态的纯 UI,不再依赖 Activity 的内部环境,调试起来方便多了。

这些改动让整个页面的代码结构焕然一新。

2. 这次重构,我觉得最值得学习的点

2.1 Route 和 Screen 的分层思想

这是我个人非常推崇的一种架构思路。我建议你把 Compose 页面分成两层来理解,这样职责会非常清晰:

  • Route:它负责“与环境打交道”。比如持有页面状态、调用 Toast、发起网络请求、处理导航逻辑。它知道“发生了什么”和“要做什么”。
  • Screen:它只负责“展示”。根据传入的状态渲染 UI,并把用户的交互事件(如输入、点击)向上抛出。它不关心数据从哪来,只关心“怎么画”。

在我的项目里,具体体现为:
- LoginRoute() 持有 usernamepasswordisSubmitting 这些状态。
- LoginScreen(...) 则根据这些状态,渲染出输入框、按钮和错误提示。

这种分层是你未来平滑迁移到 ViewModel 架构的最佳过渡方式,亲测有效。

3. 为什么新写法比原来更适合 Compose?

原来的写法当然能跑,但问题在于后续难以扩展和维护。我遇到过这些痛点:
- 业务逻辑和 UI 代码搅在一起,改起来心惊胆战。
- 想预览一个组件?得先构造出一堆依赖,非常不方便。
- 以后想加个 loading 态、错误提示或者网络请求,代码会变得越来越臃肿和混乱。

Compose 的核心思想是 “界面由状态驱动,事件向上抛出”。新的写法正是遵循了这一原则,让 UI 成为状态的纯函数,逻辑处理则集中在更上层。这样一来,代码的可测试性和可维护性都大大提升了。

4. 这次你可以重点观察的代码细节

4.1 输入状态的持久化:rememberSaveable

这次我特意用了 rememberSaveable 来记住输入框的状态,而不是普通的 remember。对于表单页来说,这一个小小的改变价值很大。它的好处是,当屏幕旋转等配置发生变化时,用户已经输入的内容有很大概率能被保留下来,体验更友好。

4.2 UI 状态的收敛:LoginFormUiState

我新增了一个 LoginFormUiState 数据类。它的作用是把所有和表单相关的状态信息都收拢到一个模型里,比如:
- 用户名
- 密码
- 是否正在提交
- 表单是否合法(允许登录)
- 当前的错误提示信息

这样做的好处是状态管理一目了然,而且它为你未来过渡到 StateFlow<LoginUiState> 这种响应式流模式铺平了道路,结构几乎不用大改。

4.3 校验逻辑的提前与声明式

以前的老思路是:用户点击登录按钮后,我们再在点击事件里判断用户名和密码“空不空”。现在的方式更接近真实业务场景:
- 输入内容一旦变化,错误状态就能实时反映在 UI 上。
- 按钮的“可点击”状态,直接由当前的表单状态推导出来,而不是写死的逻辑。

这才是 Compose 声明式编程的精髓:描述 UI 与状态的关系,而不是指挥 UI 一步步该怎么做。

5. 接下来,你可以怎么继续练习?

如果你觉得这个模式不错,想进一步巩固,我建议你可以尝试下面几个练习:

练习 1:引入 ViewModel

尝试把 LoginRoute() 里管理的本地状态,迁移到一个 LoginViewModel 中去。你可以定义:
- MutableStateFlow<LoginUiState> 作为唯一可信源。
- onUsernameChange()onPasswordChange() 等事件处理方法。
- submitLogin() 提交逻辑。

然后在页面中通过 collectAsState() 来观察状态。这是走向 MVVM 架构的关键一步。

练习 2:增加页面级的错误提示区域

目前我们只有字段级的错误提示(比如“用户名不能为空”)。你可以尝试在登录按钮上方增加一个区域,用于显示如“用户名不存在”、“密码错误”、“网络异常”等页面级错误。通过这个练习,你能很好地区分“字段级校验错误”和“业务逻辑错误”的不同处理方式。

练习 3:接入真正的导航

把登录成功后的逻辑从“弹个 Toast”升级为真正的页面跳转。比如:
- 跳转到 SettingsActivity
- 或者,如果你已经在用 Compose Navigation,可以导航到 NavHost 中定义的其他可组合项目的地。

6. 你要真正学会的,不是登录页,而是这套模式

通过这个实战,我最大的收获是掌握了一套可迁移的模式,而不仅仅是写了一个登录页。这套模式的能力在于:
- 未来所有的输入型页面(注册、修改信息、搜索)都能用这套方法写。
- 所有的提交型页面都能用“状态 + 事件”的方式来组织逻辑。
- 当未来需要接入 DataStore、网络请求、Repository 甚至更复杂的架构时,现有的结构不需要推倒重来,只需要在相应层级进行增强。

7. 建议和哪些篇章一起看?

为了更系统地理解这些概念,我建议你可以把下面几篇内容结合起来看,它们互为补充:
- 003-状态管理与ViewModel.md
- 008-副作用重组优化与调试.md
- 009-结合FirstComposeApp项目深入学习案例.md

如果你已经看完了本文,并且动手实践了,那么下一篇 011-结合FirstComposeApp重构SettingsScreen实战.md 会非常适合你继续深入。

当前文章价值0.66元,扫一扫支付后添加微信提供帮助!(如不能解决您的问题,可以申请退款)

你可能感兴趣的文章

来源:每日教程每日一例,深入学习实用技术教程,关注公众号TeachCourse
转载请注明出处: https://teachcourse.cn/3846.html ,谢谢支持!

资源分享

2026 年最前沿的 AI 工具清单 2026 年最前沿的 AI 工具清单
Android开发之gravity和layout_gravity之间的区别-案例演示 Android开发之gravity和layout_
动态给TextView控件设置权重 动态给TextView控件设置权重
Android开发Service BroadcastReceiver Handler获取当前位置 Android开发Service Broadcas

评论已关闭!