一个在职考公程序员的MVVM踩坑实录

张强
2026-08-31 23:44
阅读 767

第一坑:ViewModel里塞了太多东西

我一开始把网络请求、数据库读写、UI状态全写在ViewModel里。一个HomeViewModel写了六百多行,像个垃圾场。更要命的是,我为了让Activity“看起来干净”,把Context传进了ViewModel。每次旋转屏幕,内存泄漏警告就在Logcat里刷屏。

后来才去翻了Android Developer Kit的文档。原来ViewModel的构造参数应该通过Factory注入,而不是直接new。改成Factory模式之后,Context不再直接持有,泄漏问题消停了。但新的坑又来了。

第二坑:LiveData和协程的“状态打架”

我把网络请求写在协程里,结果用LiveData发状态。有一次用户快速切换页面,旧页面的网络回调把新页面的数据覆盖了。

后来我把UI状态统一封装成一个UiState密封类:

sealed class UiState<out T> {
    object Loading : UiState<Nothing>()
    data class Success<T>(val data: T) : UiState<T>()
    data class Error(val message: String) : UiState<Nothing>()
}

配合StateFlow替代LiveData。每次请求都带上一个请求ID,回调时校验ID是否匹配当前页面。这个方案其实是从Google ADK里的“单向数据流”思路学的。

第三坑:Angular的思维惯性害了我

公司项目是Angular写的,组件化、服务注入那套我已经形成肌肉记忆。结果写Android的时候,我习惯性地把业务逻辑写在Activity里,写到一半发现Activity快两千行了。

后来我强制自己遵循一个原则:Activity只做两件事——绑定布局和处理用户输入。 剩下的全部分层。Angular里有Service、有RxJS,Android里有Repository、有Flow,道理是一样的。这个习惯养成之后,代码清爽多了。

Kiro是什么?一个意外的救星

Kiro是我在重构过程中发现的一个轻量级状态管理库,专门解决MVVM里“状态同步”的痛点。我原本用LiveData + 手动同步,结果两个页面共享一个购物车状态时,A页面改了数量,B页面不刷新。试过EventBus、试过全局单例,都不优雅。

后来在GitHub上翻到Kiro,它的核心思路是“可观察的状态容器”,类似一个小型Redux。我把购物车状态放进一个Store里,页面订阅它,任何修改自动通知所有订阅者:

val cartStore = Kiro.store(CartState(emptyList()))

// A页面修改
cartStore.update { state ->
    state.copy(items = state.items + newItem)
}

// B页面自动收到通知
cartStore.observe { state -> renderCart(state) }

代码量少了三分之一。

写在最后

架构没有银弹,MVVM也好、MVI也好,核心是把关注点分开。就像考公一样,行测和申论要分开复习,但最后得合起来考试。

给同样在折腾移动端架构的朋友几个建议:别把ViewModel当垃圾桶;状态管理要单向流动;如果你也写Angular,记得Android不是Web,思维要切换;还有,Kiro真的可以试试,至少它拯救了我的购物车。

至于考公能不能上岸,那是另一个故事了。但不管上岸不上岸,写代码这件事,我想我会一直写下去。

评论 0

最热最新
暂无评论
张强Lv.1
0
影响力
0
文章
0
粉丝