Blog
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)

HiuZing

🍑
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)
  • 拉取安卓设备文件
  • permission
  • 常用命令
  • Android入门
  • Compose
  • MVVM架构
    • 概念
    • AndroidViewModel
    • StateFlow
    • SharedFlow
    • viewModelScope
  • 网络请求
  • 数据持久化
  • Android
HiuZing
2026-10-03
目录

MVVM架构

# 概念

内部可修改,外部只读

Model 
  ↓
ViewModel
  ↓
View
1
2
3
4
5

基本模式

class CounterViewModel : ViewModel() {

    // 私有:ViewModel 内部可以修改
    private val _count = MutableStateFlow(0)

    // 对外:只能读取
    val count = _count.asStateFlow()
}

// 流程
_count
  ↓
MutableStateFlow
  ↓
ViewModel 内部可以修改


count
  ↓
StateFlow
  ↓
Compose / 外部只能读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

业务方法

// ViewModel
class CounterViewModel : ViewModel() {

    // model
    private val _count = MutableStateFlow(0)
	// model
    val count = _count.asStateFlow()

    // 加1
    fun increment() {
        _count.value += 1    
    }

    // 重置为0
    fun reset() {
        _count.value = 0
    }
}

// View
@Composable
fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
    val count by viewModel.count.collectAsState()

    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text("数量: $count", fontSize = 40.sp)
        Spacer(modifier = Modifier.height(10.dp))
        Button(onClick = {
            viewModel.increment()
        }) {
            Text("+1")
        }
        Button(onClick = {
            viewModel.reset()
        }) {
            Text("重置")
        }
    }
}

// 流程
用户点击按钮 
→ 调用 viewModel.increment
→ ViewModel 修改 _count.value
→ StateFlow 通知观察者
→ collectAsState 收到新值
→ Compose 重组(重新渲染)
→ 界面上的数字更新
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# AndroidViewModel

类型 是否需要 Application Context 说明
ViewModel 不需要 普通 ViewModel,不能持有 Context,适合纯业务逻辑,不要在这里引用 Activity / Application,避免内存泄漏
AndroidViewModel 需要 继承自 ViewModel,构造参数携带 Application(全局上下文),可用于需要全局上下文的场景(如读取资源、数据库),不能传入 Activity Context
class LoginViewModel(
    application: Application
) : AndroidViewModel(application) {

}
1
2
3
4
5

# StateFlow

StateFlow是一个持有单个值的可观察数据流。值变化时通知所有观察者(UI 界面)自动更新。

// 创建:必须给初始值
private val _state = MutableStateFlow("初始值")

// 更新值:所有收集者会收到通知
_state.value = "新值"

// 读取当前值
println(_state.value) // 输出:新值
1
2
3
4
5
6
7
8
特点 说明 对比理解
总是有值 创建时必须给初始值 像一个变量,任何时候都有值
值相同时不通知 两次设同样的值不会触发更新 避免不必要的界面刷新
新收集者立即收到当前值 不需要等下一次变化 进入页面就能看到当前状态
适合表示 UI 状态 loading、data、error 等 持续存在的状态

例子

class QuestionViewModel : ViewModel() {
    // 模拟数据(第8讲学真实网络请求后替换)
    private val mockData = listOf(...)

    // 加载状态
    private val _loading = MutableStateFlow(value = false)
    val loading = _loading.asStateFlow()

    // 数据列表
    private val _questionList = MutableStateFlow<List<QuestionItem>>(value = emptyList())
    val questionList = _questionList.asStateFlow()

    // 发请求获取数据
    fun loadData(){
        viewModelScope.launch {
            _loading.value = true
            delay(duration = 2000.milliseconds)
            _questionList.value = mockData
            _loading.value = false
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# SharedFlow

特性 StateFlow SharedFlow
值 持有当前值(持续状态) 不持有(事件消费即消失)
重复值 相同值不通知 每次都通知
初始值 必须有 不需要
新订阅者 立即收到当前值 不收到之前的事件
适用场景 loading、data、error 等持续状态 导航跳转、Toast 提示等一次性事件

例子

class LoginViewModel : ViewModel() {
    // 持续状态用 StateFlow:加载中
    private val _loading = MutableStateFlow(false)
    val loading = _loading.asStateFlow()

    // 一次性事件用 SharedFlow:登录成功(通知UI跳转)
    // 设置1个缓冲区。如果没有收集者时 emit 会挂起等待,设置缓冲区后事件不会丢失
    private val _loginSuccess = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
    val loginSuccess = _loginSuccess.asSharedFlow()

    // 一次性事件用 SharedFlow:错误消息(通知UI显示Toast)
    private val _error = MutableSharedFlow<String>(extraBufferCapacity = 1)
    val error = _error.asSharedFlow()

    // 模拟用户数据(正式项目第9讲用 AuthManager 持久化)
    private val validateUsers = mapOf(
        "admin" to "123456",
        "test" to "test123"
    )

    fun login(username: String, password: String) {
        if (_loading.value) return

        viewModelScope.launch {
            _loading.value = true
            delay(duration = 2000.milliseconds)
            if (validateUsers[username] == password) {
                // 登录成功 -> 发射成功事件
                _loginSuccess.emit(value = Unit)
            } else {
                // 登录失败 -> 发射错误事件
                _loginError.emit(value = "用户名或密码错误")
            }
        }
    }

}

// UI层
@Composable
fun LoginScreen(viewModel: LoginViewModel = viewModel()) {
    // 状态变量
    var username by remember { mutableStateOf(value = "") }
    var password by remember { mutableStateOf(value = "") }

    val loading by viewModel.loading.collectAsState()

    val context = LocalContext.current

    // 收集登录成功事件
    LaunchedEffect(key1 = Unit) {
        viewModel.loginSuccess.collect {
            Toast.makeText(context, text = "登录成功,token:$it", duration = Toast.LENGTH_SHORT).show()
        }
    }

    // 收集登录失败事件
    // 下面可以继续写LaunchedEffect收集loginError

    // UI布局...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

_loading:StateFlow 用于持续 UI 状态,页面是否正在加载,UI 通过collectAsState订阅,用来展示加载动画。

_loginSuccess / _error:MutableSharedFlow 用于一次性事件:登录成功跳转、弹出错误 Toast。

# viewModelScope

viewModelScope 是 ViewModel专属的协程作用域,生命周期绑定 ViewModel。

class MyViewModel : ViewModel() {
    fun loadData() {
        // viewModelScope 绑定 ViewModel 生命周期
        // ViewModel 销毁时自动取消所有协程
        viewModelScope.launch {
            delay(2000)        // 模拟耗时操作
            println("数据加载完成") // 在 Logcat 中查看
        }
    }
}
1
2
3
4
5
6
7
8
9
10

·

上次更新: 2026/10/07, 07:27:34
Compose
网络请求

← Compose 网络请求→

最近更新
01
02
数据持久化
10-06
03
网络请求
10-04
更多文章>
Theme by Vdoing | Copyright © 2021-2026 WeiXiaojing | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式