LiveData 完整笔记
1️⃣ 添加依赖
dependencies {
// LiveData
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
// ViewModel + 协程(配合使用)
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
}
2️⃣ 基本用法
// ViewModel
class MainViewModel : ViewModel() {
// 私有可变,公开只读
private val _count = MutableLiveData(0)
val count: LiveData<Int> = _count
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
}
// Activity
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val tvCount = findViewById<TextView>(R.id.tvCount)
val btnAdd = findViewById<Button>(R.id.btnAdd)
// 观察数据变化
viewModel.count.observe(this) { count ->
tvCount.text = "计数:$count"
}
btnAdd.setOnClickListener {
viewModel.increment()
}
}
}
3️⃣ 两种赋值方式
| 方法 |
线程要求 |
使用场景 |
setValue() |
必须主线程 |
主线程更新 |
postValue() |
任意线程 |
子线程更新 |
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun updateOnMain() {
_data.value = "主线程数据" // setValue
}
fun updateOnBackground() {
viewModelScope.launch(Dispatchers.IO) {
val result = fetchData()
_data.postValue(result) // postValue
}
}
}
class MyViewModel : ViewModel() {
private val _input = MutableLiveData<String>()
val input: LiveData<String> = _input
// map:数据转换
val upperCase = Transformations.map(input) { text ->
text.uppercase()
}
// switchMap:切换数据源
private val _userId = MutableLiveData("1")
val userData = Transformations.switchMap(_userId) { userId ->
repository.getUser(userId) // 返回 LiveData
}
}
class MyViewModel : ViewModel() {
private val _name = MutableLiveData("张三")
private val _age = MutableLiveData(25)
// 合并两个数据源
val combined = MediatorLiveData<String>().apply {
addSource(_name) { name ->
value = "姓名:$name,年龄:${_age.value}"
}
addSource(_age) { age ->
value = "姓名:${_name.value},年龄:$age"
}
}
}
6️⃣ 协程 + LiveData 配合(最常用)
class UserViewModel : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
private val _loading = MutableLiveData(false)
val loading: LiveData<Boolean> = _loading
private val _error = MutableLiveData<String?>()
val error: LiveData<String?> = _error
fun loadUser(userId: String) {
viewModelScope.launch {
_loading.value = true
_error.value = null
try {
val result = apiService.getUser(userId) // suspend 网络请求
_user.value = result
} catch (e: Exception) {
_error.value = e.message
} finally {
_loading.value = false
}
}
}
}
7️⃣ UI 层使用
class UserActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
// 观察多个状态
viewModel.user.observe(this) { user ->
showUserInfo(user)
}
viewModel.loading.observe(this) { isLoading ->
progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
}
viewModel.error.observe(this) { error ->
error?.let { toast(it) }
}
// 加载数据
viewModel.loadUser("123")
}
}
8️⃣ LiveData 的坑和解决方案
❌ 问题1:数据粘性(新观察者收到旧数据)
// 默认行为:新注册的 Observer 会立即收到最后一条数据
viewModel.data.observe(this) {
// 会立刻收到旧数据
}
✅ 解决方案 :使用 StateFlow 或自定义 SingleLiveEvent
// 方案1:改用 StateFlow
private val _data = MutableStateFlow<String?>(null)
val data: StateFlow<String?> = _data
// 方案2:自定义 SingleLiveEvent(只通知一次)
class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner) { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
}
override fun setValue(value: T) {
pending.set(true)
super.setValue(value)
}
}
❌ 问题2:内存泄漏
// ✅ 正确:使用 lifecycleScope 自动管理
viewModel.data.observe(viewLifecycleOwner) { // Fragment 用 viewLifecycleOwner
// Activity 销毁时自动移除
}
// ❌ 错误:手动添加不移除会泄漏
viewModel.data.observeForever {
// 必须手动 removeObserver
}
9️⃣ LiveData vs StateFlow 对比
| 特性 |
LiveData |
StateFlow |
| 生命周期感知 |
✅ 自动 |
❌ 需手动处理 |
| 初始值 |
可选 |
必须有 |
| 数据粘性 |
✅ 有 |
✅ 有 |
| 背压处理 |
❌ 不支持 |
✅ 支持 |
| 数据操作(map/filter) |
有限 |
丰富 |
| 配合协程 |
一般 |
原生支持 |
| 适用场景 |
简单 UI 状态 |
复杂数据流 |
// LiveData 写法
private val _state = MutableLiveData(State())
val state: LiveData<State> = _state
// StateFlow 写法
private val _state = MutableStateFlow(State())
val state: StateFlow<State> = _state
🔟 完整实战示例
// 1. 数据层
interface ApiService {
suspend fun getArticles(): List<Article>
}
// 2. Repository
class ArticleRepository(private val api: ApiService) {
suspend fun fetchArticles(): List<Article> {
delay(1000)
return api.getArticles()
}
}
// 3. ViewModel
class ArticleViewModel : ViewModel() {
private val repository = ArticleRepository(MockApi())
private val _articles = MutableLiveData<List<Article>>(emptyList())
val articles: LiveData<List<Article>> = _articles
private val _loading = MutableLiveData(false)
val loading: LiveData<Boolean> = _loading
private val _error = MutableLiveData<String?>()
val error: LiveData<String?> = _error
fun loadArticles() {
viewModelScope.launch {
_loading.value = true
_error.value = null
try {
val data = withContext(Dispatchers.IO) {
repository.fetchArticles()
}
_articles.value = data
} catch (e: Exception) {
_error.value = e.message
} finally {
_loading.value = false
}
}
}
}
// 4. Activity
class ArticleActivity : AppCompatActivity() {
private val viewModel: ArticleViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_article)
viewModel.articles.observe(this) { articles ->
// 更新 RecyclerView
}
viewModel.loading.observe(this) { loading ->
// 显示/隐藏 ProgressBar
}
viewModel.error.observe(this) { error ->
error?.let { showError(it) }
}
viewModel.loadArticles()
}
}
📝 面试必备口诀
LiveData 观察者,生命周期感知强
set 主线程,post 子线程
配合协程拿数据,更新 UI 自动来
注意粘性问题,StateFlow 是升级版