LiveData 相关问题是面试高频题,因为他具有生命周期感知能力,支持黏性事件,采用了观察者模式,某种程度上也可以用作事件总线。
根据官方文档我们知道它的主要作用:数据持有存储器类、可观察类、具有生命周期感知能力。
问题来了:
-
LiveData 怎么感知生命周期感知?需要取消注册吗?
-
setValue 和 postValue 有什么区别
-
设置相同的值,订阅的观察者们会收到同样的值吗
-
粘性事件原理,怎么防止数据倒灌
-
observeForever怎么用
基本使用
====
MainRepository
class MainRepository {
suspend fun getNameList(): List {
// 获取数据切到工作线程,模拟网络请求过程
return withContext(Dispatchers.IO) {
listOf(“张三”, “李四”)
}
}
}
MainViewModel
class MainViewModel: ViewModel() {
private val nameList = MutableLiveData<List>()
val nameListResult: LiveData<List> = nameList
private val mainRepository = MainRepository()
fun getNames() {
// 使用协程模拟请求过程
viewModelScope.launch {
nameList.value = mainRepository.getNameList()
}
}
}
MainActivity
class MainActivity : AppCompatActivity() {
// 创建 ViewModel 方式 1
// 通过 kotlin 委托特性创建 ViewModel
// 需添加依赖 implementation ‘androidx.activity:activity-ktx:1.2.3’
// viewModels() 内部也是通过 创建 ViewModel 方式 2 来创建的 ViewModel
private val mainViewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate (savedInstanceState)
setContentView(R.layout.activity_main)
// 创建 ViewModel 方式 2
val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// 通过 LiveData.observe 订阅观察者
mainViewModel.nameListResult.observe(this, {
Log.i(“MainActivity”, “mainViewModel: nameListResult: $it”)
})
mainViewModel.getNames()
}
}
打开app -> 正常看到日志
18:03:02.575 : mainViewModel: nameListResult: [张三, 李四]
源码解析
====
LiveData 通过 observe 方法来订阅观察者,以此为查看源码的入口:
方法注释包含的知识很多,请认真阅读注释 (百度翻译过来的)。
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
new SafeIterableMap<>();
/**
-
1、在给定 owner 的生命周期内,将给定的观察者添加到观察者列表中。
-
2、事件在主线程上调度。
-
3、如果LiveData已经有数据集,它将被交付给观察者。
-
-
4、仅当所有者处于{@link Lifecycle.State#STARTED}或{@link Lifecycle.State#RESUME}状态
*(活动)时,观察者才会接收事件。
-
-
5、如果所有者移动到{@link Lifecycle.State#DETROYED}状态,观察者将自动被删除。
-
-
6、当数据在{@code owner}未激活时发生更改时,它将不会收到任何更新。
-
7、如果它再次激活,它将自动接收最后可用的数据。
-
-
8、只要给定的LifecycleOwner未被销毁,LiveData就会保留对观察者和所有者的强引用。
-
9、销毁后,LiveData将删除对所有者的引用。
-
-
10、如果给定的所有者已经处于{@link Lifecycle.State#DESTROYED}状态,LiveData将忽略该调用。
-
-
11、如果给定的所有者、观察者元组已经在列表中,则忽略该调用。
-
12、如果观察者已经列表中,LiveData将抛出@link IllegalArgumentException}。