Android 架构这些年,其实一直在消灭碎片化异步

工作几年才发现:

text 复制代码
真正折磨人的根本不是线程。

而是这些东西:

  • callback 一层套一层
  • Activity 都退出了任务还在跑
  • 页面销毁了回调突然回来了
  • 数据更新顺序乱掉
  • Handler、Rx、LiveData、Flow 混着用
  • 每个 SDK 都有自己的一套回调体系

最后项目慢慢变成:

一个巨大的异步缝合怪。

而这,其实才是 Android 大型项目真正的复杂度来源。


一、Android 最早其实没有统一异步方案

回头看看 Android 的发展历史,你会发现:

Android 从来都不缺异步方案。

缺的是:

一个统一的异步方案。


Thread + Handler 时代

最早大家都是这么写:

kotlin 复制代码
Thread {
    val data = request()

    handler.post {
        updateUi(data)
    }
}.start()

刚学的时候觉得:

text 复制代码
好简单啊。

后来项目大了以后发现:

  • 线程谁创建?
  • 谁销毁?
  • 谁切主线程?
  • 页面退出怎么办?
  • 回调回来页面没了怎么办?

写着写着就开始出现:

text 复制代码
if(activity.isFinishing) return
text 复制代码
if(fragment.isAdded)
text 复制代码
WeakReference<Activity>

整个代码开始变得越来越奇怪,也越来越难维护。


AsyncTask 时代

后来 Google 觉得:

text 复制代码
直接操作 Thread 太难了。

于是推出了:

kotlin 复制代码
doInBackground()

onPostExecute()

当时感觉简直就是神器。

结果几年后大家发现:

它其实只是:

text 复制代码
把 callback 换了个地方写。

问题一个都没解决。

最后甚至被官方直接废弃。


Listener 大爆炸时代

后来 Android 系统越来越复杂。

各种 Listener 开始疯狂增长:

  • LocationListener
  • SensorListener
  • BluetoothListener
  • MediaPlayerListener
  • CameraListener
  • SurfaceListener

然后你会发现:

每个系统组件都有自己的玩法。

有的:

text 复制代码
回调主线程

有的:

text 复制代码
回调 Binder 线程

有的:

text 复制代码
必须手动 unregister

有的:

text 复制代码
生命周期自动结束

还有一些第三方 SDK:

text 复制代码
文档都不告诉你在哪个线程回调。

于是整个项目开始进入:

万物皆回调时代。


二、真正复杂的,是线程之间的协作。

很多人觉得:

text 复制代码
异步难 = 多线程难

其实完全不是。

举个最常见的业务:

text 复制代码
请求用户信息
↓

拿到用户 ID

↓

请求订单列表

↓

写入数据库

↓

通知 UI 更新

↓

页面退出时自动取消

这里最难的地方其实根本不是:

text 复制代码
开线程。

而是:

text 复制代码
这一整套流程谁来管理?

什么时候取消?

异常怎么传?

页面销毁怎么办?

谁负责切线程?

谁负责回调 UI?

这些才是真正麻烦的地方。


三、最可怕的是每层都有自己的异步模型

比如一个老项目可能长这样:

网络层:

text 复制代码
Callback

数据库:

text 复制代码
RxJava

UI:

text 复制代码
LiveData

系统事件:

text 复制代码
Handler

IM:

text 复制代码
Listener

最后业务代码变成:

text 复制代码
Callback 套 Rx

Rx 转 LiveData

LiveData 再转 Flow

Flow 最后再 collect

整个项目像一个异步中转站。

你根本不知道:

数据到底从哪里来的。

又会在什么时候回来。


四、RxJava 第一次让大家看到希望

RxJava 当年为什么这么火?

因为它第一次告诉大家:

text 复制代码
别管什么网络请求、按钮点击、数据库变化。

统统都是流。

网络请求是流。

数据库变化是流。

按钮点击也是流。

甚至定时器都是流。

突然之间:

整个项目终于开始说同一种语言了。

这也是为什么:

那几年 Android 基本就是:

text 复制代码
不会 RxJava 都不好意思投简历。

五、但 RxJava 最大的问题是:

它终究只是一个库。

换句话说:

text 复制代码
你会 Rx 才能玩。

不会?

那项目基本看不懂。

尤其这种代码:

kotlin 复制代码
flatMap()
switchMap()
zip()
combineLatest()
observeOn()
subscribeOn()

新人看到基本直接投降。

而且:

Rx 世界。

Callback 世界。

Kotlin 世界。

很多时候还是三套体系同时存在。

项目依旧会慢慢变成:

text 复制代码
异步缝合怪。

六、协程真正厉害的地方

Kotlin 协程最厉害的地方其实是:

text 复制代码
异步终于变成语言能力了,以及把复杂的异步变成线性的可控的。

以前:

text 复制代码
异步靠框架。

现在:

text 复制代码
异步直接写进语言里。

于是:

kotlin 复制代码
val user = api.getUser()

val order = api.getOrder(user.id)

dao.insert(order)

看起来像同步。

实际上全是异步。

代码终于开始重新变得像人写的了。


七、Flow 真正解决的是:

终于不用到处转来转去了。

以前:

text 复制代码
Callback -> Rx -> LiveData -> UI

现在:

text 复制代码
Flow -> UI

网络:

kotlin 复制代码
Flow<User>

数据库:

kotlin 复制代码
Flow<List<Article>>

WebSocket:

kotlin 复制代码
Flow<Message>

蓝牙状态:

kotlin 复制代码
Flow<BluetoothState>

UI 状态:

kotlin 复制代码
StateFlow<UiState>

整个项目终于开始说一种语言。

这件事其实比性能优化重要得多。

因为:

架构最怕的就是乱


八、Compose 为什么疯狂拥抱 Flow

因为它俩本来就是一家的。

Compose:

text 复制代码
状态变了
↓

UI 自动刷新

Flow:

text 复制代码
数据变了
↓

状态自动更新

所以:

kotlin 复制代码
val uiState by viewModel.uiState.collectAsState()  这里是举例,生产环境要使用正确的withlife 那个。

九、这些年 Android 架构升级,

其实一直都在解决同一个问题。

表面上看:

text 复制代码
MVVM
MVI
Compose
Flow
StateFlow
UDF

像是各种新名词不断冒出来。

但本质上它们都在做一件事:

把失控的异步重新关进规则里。

因为大型项目真正可怕的从来不是:

text 复制代码
功能太多。

而是:

text 复制代码
异步失控。

什么时候执行?

什么时候取消?

谁先回来?

谁后回来?

谁负责更新状态?

这些问题如果没人管。

项目迟早会变成:

text 复制代码
谁改谁背锅。

最后

Android 架构这些年的演化。

表面上看是在:

text 复制代码
升级 API
更换框架
更新架构

但底层其实一直都在做同一件事:

消灭异步缝合怪。

从 Thread 到 Handler。

从 AsyncTask 到 RxJava。

从 RxJava 到 Coroutine。

从 LiveData 到 Flow。

从 XML 到 Compose。

技术一直在变。

但 Android 工程师和异步战斗这件事,

十几年了,到了协程,总算熬到了头。

参考

从 Callback 到 Coroutines:Android 异步并发方案的演进

"结构化"这个词,本质上就是------把混乱的东西变成有组织、有规则、有边界的东西

从"调用方的如履薄冰"到"接口的天然语义":Room/DataStore/Retrofit 的启示

现代 Android 官方为什么更推荐 Repository 暴露 suspend fun,而不是在内部 launch

# Android 架构指南之Data 层不要再暴露 start/stop 了:用 Flow 接管生命周期

别再 launch(IO) 了:协程线程切换的 3隐藏反模式

从送外卖看Android Clean架构:为什么老板不需要知道外卖员开什么车

用一个小 Demo,带你入门安卓 Clean Architecture

Android 现代架构不需要事件总线

为什么我不在 Android ViewModel 中直接处理异常?

相关推荐
plainGeekDev17 小时前
依赖管理 → Version Catalog
android·java·kotlin
韩曙亮19 小时前
【Flutter】Flutter 进程保活 ③ ( 屏幕常亮设置 | Flutter 禁止息屏、关闭自动锁屏、屏蔽系统屏保 )
android·flutter·ios·屏幕常亮·禁止息屏
爱笑鱼19 小时前
NDK、SDK、APP、Framework、Native 到底怎么区分?
android
私人珍藏库20 小时前
[Android] 发票制作器-内置多行业专业模板
android·人工智能·app·软件·多功能
阿pin20 小时前
Android随笔-PMS
android·pms
悲凉的紫菜21 小时前
dariy
android·ide·android studio
2501_915909061 天前
IPA 深度混淆是什么意思?从混淆强度到实际效果的解读
android·ios·小程序·https·uni-app·iphone·webview
LT10157974441 天前
2026年手机机型兼容性测试选型指南:安卓机型碎片化、APP闪退UI错乱如何解决
android·测试工具·ui·智能手机
阿pin1 天前
Android随笔-view是如何显示到屏幕上
android·view