当前位置: 首页 > news >正文

Jetpack Compose + 协程(Coroutine)完整实战教程

Jetpack Compose + 协程(Coroutine)完整实战教程

现代 Android 开发里:

Compose + 协程 + Flow

已经是官方主流架构。

如果你只会:

Button(onClick={})

但不会:

  • LaunchedEffect
  • rememberCoroutineScope
  • StateFlow
  • collectAsState
  • Compose 生命周期协程

那基本还没进入真正的 Compose 开发。

这一篇从:原理 → 生命周期 → 实战 → 架构完整讲透。


一、为什么 Compose 特别依赖协程?

因为:

Compose 是:声明式 UI

UI 本身:状态变化 → 自动刷新

而协程非常适合:

  • 异步请求
  • 状态更新
  • Flow 数据流
  • UI 生命周期

所以:Compose 和协程天然契合。


二、Compose 中最重要的协程 API

API作用
LaunchedEffect页面生命周期协程
rememberCoroutineScope手动启动协程
collectAsState收集 Flow
produceState协程转 State
snapshotFlowState 转 Flow

三、LaunchedEffect(最核心)

这是 Compose 协程第一核心


四、第一个 LaunchedEffect

@ComposablefunTestPage(){LaunchedEffect(Unit){delay(2000)println("执行")}}

它是什么?

本质:Compose 生命周期协程

  • 当 Composable 进入界面:自动启动协程
  • 离开界面:自动取消协程

五、为什么不能直接 launch?

很多新人这样写:

@ComposablefunTest(){GlobalScope.launch{// ...}}

这是错误的。

因为:

  • Composable 会频繁重组(Recompose)
  • 可能疯狂创建协程
  • 导致:内存泄漏、重复请求、协程爆炸

六、LaunchedEffect 生命周期

阶段行为
进入 Composition启动协程
离开 Composition取消协程
key 改变重新启动协程

七、key 的作用(非常重要)

LaunchedEffect(userId){loadUser(userId)}

userId变化时:

  • 取消旧协程
  • 启动新协程

八、LaunchedEffect(Unit)

最常见。

LaunchedEffect(Unit)

表示:仅首次进入执行一次,类似Activity.onCreate()


九、Compose 倒计时

@ComposablefunCountDown(){vartimebyremember{mutableStateOf(10)}LaunchedEffect(Unit){while(time>0){delay(1000)time--}}Text("$time")}

为什么 UI 自动刷新?因为mutableStateOf状态变化后,Compose 自动重组 UI。


十、rememberCoroutineScope

第二核心。


十一、为什么需要它?

因为:Button点击时不能直接调用 suspend

错误:

Button(onClick={delay(1000)// onClick 不是 suspend})

十二、正确写法

@ComposablefunTest(){valscope=rememberCoroutineScope()Button(onClick={scope.launch{delay(1000)println("点击")}}){Text("按钮")}}

十三、rememberCoroutineScope 本质

它返回与当前 Composition 绑定的 CoroutineScope,页面销毁自动 cancel。


十四、LaunchedEffect vs rememberCoroutineScope

这是高频面试题。

LaunchedEffectrememberCoroutineScope
适合:自动执行任务适合:用户事件触发
页面初始化Button 点击
自动请求手势事件
倒计时Snackbar
Flow 收集

十五、Compose + ViewModel

现代 Android 标准方案。

ViewModel

classUserViewModel:ViewModel(){varuserbymutableStateOf<User?>(null)privatesetfunloadUser(){viewModelScope.launch{user=api.getUser()}}}

Compose

@ComposablefunUserPage(vm:UserViewModel=viewModel()){LaunchedEffect(Unit){vm.loadUser()}Text(vm.user?.name?:"")}

为什么不用 lifecycleScope?

  • Compose 推荐ViewModelScope
  • UI 只负责显示状态

十六、Compose + StateFlow(现代官方方案)

这是最重要的。

ViewModel

classUserViewModel:ViewModel(){privateval_uiState=MutableStateFlow<User?>(null)valuiState=_uiState.asStateFlow()funload(){viewModelScope.launch{_uiState.value=api.getUser()}}}

Compose 收集 Flow

@ComposablefunUserPage(vm:UserViewModel=viewModel()){valuserbyvm.uiState.collectAsState()Text(user?.name?:"")}

十七、collectAsState 本质

它将Flow → Compose State,当 Flow 发射新数据,自动重组 UI。


十八、完整执行流程(最重要)

ViewModelScope ↓ 网络请求 ↓ StateFlow更新 ↓ collectAsState收到 ↓ Compose自动重组 ↓ UI刷新

这就是:现代 Android UI 响应式架构


十九、Compose + Retrofit + 协程

完整现代写法。

Repository

classUserRepository{suspendfungetUser()=api.getUser()}

ViewModel

classUserViewModel:ViewModel(){privatevalrepository=UserRepository()varuserbymutableStateOf<User?>(null)privatesetfunloadUser(){viewModelScope.launch{user=repository.getUser()}}}

Compose UI

@ComposablefunUserScreen(vm:UserViewModel=viewModel()){LaunchedEffect(Unit){vm.loadUser()}Text(vm.user?.name?:"")}

二十、为什么不在 Compose 直接请求网络?

错误:

LaunchedEffect(Unit){api.getUser()}

因为:UI 不应该直接操作数据层,否则不好测试、生命周期混乱、逻辑耦合


二十一、Compose 中的协程取消

Compose 生命周期结束,自动 cancel

例如LaunchedEffect离开页面,协程自动结束。


二十二、rememberUpdatedState(高级)

经典问题:LaunchedEffect 内拿到旧值。

vallatestCallbackbyrememberUpdatedState(onClick)

作用:始终拿到最新 lambda,避免闭包旧引用问题。


二十三、produceState

作用:协程 → State

valuserbyproduceState<User?>(null){value=api.getUser()}

本质:内部其实就是LaunchedEffect + mutableStateOf


二十四、snapshotFlow

作用:Compose State → Flow

snapshotFlow{text}.collect{// ...}

适合:搜索监听、输入变化、滚动监听。


二十五、Compose 搜索防抖(经典实战)

ViewModel

classSearchViewModel:ViewModel(){valkeyword=MutableStateFlow("")init{viewModelScope.launch{keyword.debounce(500).collect{search(it)}}}}

Compose

TextField(value=text,onValueChange={text=it vm.keyword.value=it})

二十六、Snackbar 协程

这是rememberCoroutineScope高频场景。

valsnackbarHostState=remember{SnackbarHostState()}valscope=rememberCoroutineScope()Button(onClick={scope.launch{snackbarHostState.showSnackbar("成功")}}){}

二十七、Compose 动画为什么也用协程?

Compose 动画很多本质也是 suspend。例如:

Animatable.animateTo()

内部:协程驱动帧刷新


二十八、Compose 中常见错误

错误说明
在 Composable 直接GlobalScope.launch生命周期不可控
重组导致重复请求api.getUser()直接写在 UI
collect没有生命周期flow.collect可能泄漏

二十九、正确的 Flow 收集

推荐:collectAsState()

或者:collectAsStateWithLifecycle()(官方推荐)


三十、collectAsStateWithLifecycle

implementation"androidx.lifecycle:lifecycle-runtime-compose"
valuiStatebyvm.uiState.collectAsStateWithLifecycle()

为什么推荐它?自动处理生命周期,页面不可见自动暂停收集。


三十一、Compose + Room + Flow

现代数据库方案。

DAO

@Query("SELECT * FROM user")fungetUsers():Flow<List<User>>

Compose

valusersbydao.getUsers().collectAsState(initial=emptyList())

数据库变化,UI 自动刷新。


三十二、Compose + Paging3 + 协程

现代列表方案。

ViewModel

Pager(...).flow.cachedIn(viewModelScope)

Compose

collectAsLazyPagingItems()

三十三、Compose 协程源码核心

最核心:

  • Recomposer
  • CoroutineScope
  • MonotonicFrameClock

Compose 本质:也是协程驱动。


三十四、Compose 为什么不卡 UI?

因为:

  • suspend不阻塞线程
  • Recomposer分帧执行
  • 状态驱动刷新

三十五、Compose 协程面试题

1. LaunchedEffect 和 rememberCoroutineScope 区别?

API用途
LaunchedEffect自动生命周期任务
rememberCoroutineScope用户事件协程

2. collectAsState 本质?

Flow → State

3. Compose 为什么容易重复请求?

因为:重组(Recomposition)

4. 为什么不用 GlobalScope?

因为:生命周期不可控

5. Compose 官方推荐状态方案?

StateFlow+collectAsStateWithLifecycle


三十六、现代 Compose 最佳架构(企业级)

Compose UI ↓ ViewModel ↓ StateFlow ↓ Repository ↓ Retrofit / Room

三十七、真正理解 Compose + 协程

Compose 真正核心:UI = State 的函数

而协程负责:异步修改 State

最终:State变化 → Compose自动重组 → UI自动刷新

这就是现代 Android 的本质。


三十八、真正的大脑模型(最重要)

看到LaunchedEffect,自动想到:

Composition生命周期 + CoroutineScope + 自动取消

看到collectAsState(),自动想到:

Flow → State → Recomposition

看到viewModelScope.launch,自动想到:

协程 → 更新StateFlow → Compose刷新UI

三十九、最后一句(Compose 为什么这么强)

传统 AndroidCompose
手动找View状态驱动UI
手动刷新UI协程驱动异步
手动管理生命周期Flow驱动数据流

这就是Google 现在整个 Android UI 架构的核心方向。

http://www.jsqmd.com/news/818872/

相关文章:

  • 终极指南:如何用AnyKernel3一键创建完美Android内核刷机包
  • 思维导图效率革命:Freeplane专业模板库的完整解决方案
  • 告别模态混叠:用Python手把手实现经验小波变换(EWT)信号分解
  • 2025最权威的AI写作神器推荐榜单
  • 智能体框架构建指南:从核心原理到工程实践
  • Ricon组态系统:工业组件开发指南与实践
  • React Hook实现Claude模型智能路由:策略模式在AI对话系统中的应用
  • 学术研究项目利用Taotoken聚合平台便捷调用不同模型进行对比实验
  • 保姆级教程:用MATLAB搞定GM(1,1)预测模型的三大检验(附完整代码)
  • 基于 HarmonyOS 6.0 的智能记账页面开发实践:ArkUI 页面构建与跨端设计深度解析
  • 如何快速实现跨平台输入法词库转换:开源工具的完整指南
  • 魔兽争霸3帧率解锁与界面修复:3步彻底解决卡顿和显示异常问题
  • 你的iPhone在Windows上无法上网共享?2分钟修复方案来了!
  • Kotlin 协程与挂起函数(Coroutines suspend)入门到实战
  • 1.5A,30VIN,XZ4120,降压恒流LED驱动芯片 SOT89-5,ESOP8
  • rpc和http的区别
  • 【开源】电商运营场景的 Agent :EcomPilot经营诊断神器 附github
  • Android Studio的安装及配置 创建项目编译、运行、调试、打包安装包
  • Parsec VDD虚拟显示器终极实战指南:从零构建高性能游戏串流环境
  • innovus : assignPGBumps assignsignalbump
  • 保姆级教程:用Python手写牛顿迭代法求平方根(附完整代码与可视化)
  • OBS Advanced Timer:6种专业计时模式让直播时间管理更精准
  • 基于LLM的BI工具AI助手:自然语言查询与数据分析实践
  • 2026年液压坝技术全解析:溢流闸、船闸、节制闸、蓄水坝、钢坝、钢闸门、防洪闸、合页坝、底轴旋转坝、弧形闸门、拦河坝选择指南 - 优质品牌商家
  • 大数据“杀熟”将被严查:技术人如何用中间件构建合规的数据治理体系?
  • 如何在项目中引入googtest(上)——通过编译器引入库
  • 量子变分算法中的参数偏移规则与梯度估计优化
  • 2026年5月西安老房改造避坑指南:为何业之峰装饰集团未央分公司是可靠之选? - 2026年企业推荐榜
  • 本专栏配套项目概览:一个可对话、可搜索、可生成报告的智能助手
  • Excel中以当前列的数值作为查找条件,查找匹配的行