一、測試概述
本測試旨在驗證在不同 ViewModelStoreOwner 和 LifecycleOwner 配置下,Activity 和 Fragment 對 LiveData 的觀察行為。
核心概念
-
ViewModelStoreOwner: 決定 ViewModel 實例的存儲位置和共享范圍
- 使用
Activity作為 ViewModelStoreOwner:Activity 和所有使用 Activity 的 Fragment 共享同一個 ViewModel 實例 - 使用
Fragment作為 ViewModelStoreOwner:每個 Fragment 擁有獨立的 ViewModel 實例
- 使用
-
LifecycleOwner: 決定 LiveData 觀察者的生命周期綁定
- 使用
Activity作為 LifecycleOwner:觀察者綁定到 Activity 的生命周期 - 使用
Fragment作為 LifecycleOwner:觀察者綁定到 Fragment 的生命周期
- 使用
二、測試場景與結果
場景1:Fragment1 使用 Activity 的 ViewModelStoreOwner 和 LifecycleOwner
setValue 來源: Activity 的 viewModel
測試說明: Activity 調(diào)用 setValue,Activity 未 observe
| 組件 | ViewModelStoreOwner | LifecycleOwner | 是否 observe | 觀察結果 |
|---|---|---|---|---|
| Activity | Activity | Activity | ? 未 observe | - |
| Fragment1 | Activity | Activity | ? observe | ? 觀察到 |
| Fragment2 | Fragment | Fragment | ? observe | ? 無法觀察到 |
結論: Fragment1 與 Activity 共享 ViewModel 實例,可以觀察到 Activity 設置的值;Fragment2 使用獨立的 ViewModel 實例,無法觀察到。
場景2:Fragment1 使用 Activity 的 ViewModelStoreOwner,F(xiàn)ragment 自身的 LifecycleOwner
setValue 來源: Activity 的 viewModel
測試說明: Activity 調(diào)用 setValue,Activity 未 observe
| 組件 | ViewModelStoreOwner | LifecycleOwner | 是否 observe | 觀察結果 |
|---|---|---|---|---|
| Activity | Activity | Activity | ? 未 observe | - |
| Fragment1 | Activity | Fragment | ? observe | ? 觀察到 |
| Fragment2 | Fragment | Fragment | ? observe | ? 無法觀察到 |
結論: Fragment1 雖然使用 Fragment 作為 LifecycleOwner,但因為與 Activity 共享 ViewModel 實例,仍能觀察到 Activity 設置的值。
場景3:Fragment1 使用 Fragment 的 ViewModelStoreOwner,Activity 的 LifecycleOwner
setValue 來源: Activity 的 viewModel
測試說明: Activity 調(diào)用 setValue,Activity 未 observe
| 組件 | ViewModelStoreOwner | LifecycleOwner | 是否 observe | 觀察結果 |
|---|---|---|---|---|
| Activity | Activity | Activity | ? 未 observe | - |
| Fragment1 | Fragment | Activity | ? observe | ? 無法觀察到 |
| Fragment2 | Fragment | Fragment | ? observe | ? 無法觀察到 |
結論: Fragment1 使用獨立的 ViewModel 實例,即使使用 Activity 作為 LifecycleOwner,也無法觀察到 Activity 的 ViewModel 實例的變化。
場景4:Activity 和 Fragment1 都使用 Activity 的 ViewModelStoreOwner 和 LifecycleOwner
setValue 來源: Fragment1 的 viewModel
測試說明: Fragment1 調(diào)用 setValue,Activity 也 observe
| 組件 | ViewModelStoreOwner | LifecycleOwner | 是否 observe | 觀察結果 |
|---|---|---|---|---|
| Activity | Activity | Activity | ? observe | ? 觀察到 |
| Fragment1 | Activity | Activity | ? observe | ? 觀察到 |
| Fragment2 | Fragment | Fragment | ? observe | ? 無法觀察到 |
結論: Activity 和 Fragment1 共享同一個 ViewModel 實例,當 Fragment1 設置值時,Activity 和 Fragment1 都能觀察到變化;Fragment2 使用獨立的 ViewModel 實例,無法觀察到。
場景5:Fragment1 使用 Fragment 的 ViewModelStoreOwner,Activity 的 LifecycleOwner
setValue 來源: Fragment1 的 viewModel
測試說明: Fragment1 調(diào)用 setValue,Activity 也 observe
| 組件 | ViewModelStoreOwner | LifecycleOwner | 是否 observe | 觀察結果 |
|---|---|---|---|---|
| Activity | Activity | Activity | ? observe | ? 無法觀察到 |
| Fragment1 | Fragment | Activity | ? observe | ? 觀察到 |
| Fragment2 | Fragment | Fragment | ? observe | ? 無法觀察到 |
結論: Fragment1 使用獨立的 ViewModel 實例,當 Fragment1 設置值時,只有 Fragment1 能觀察到自己的 ViewModel 變化;Activity 雖然 observe,但因為使用的是不同的 ViewModel 實例,無法觀察到 Fragment1 設置的值。
三、關鍵發(fā)現(xiàn)總結
1. ViewModelStoreOwner 的作用
| ViewModelStoreOwner | 效果 |
|---|---|
| Activity | Activity 和所有使用 Activity 的 Fragment 共享同一個 ViewModel 實例 |
| Fragment | 每個 Fragment 擁有獨立的 ViewModel 實例,互不影響 |
2. LifecycleOwner 的作用
| LifecycleOwner | 效果 |
|---|---|
| Activity | 觀察者綁定到 Activity 的生命周期,Activity 銷毀時自動移除觀察者 |
| Fragment | 觀察者綁定到 Fragment 的生命周期,F(xiàn)ragment 銷毀時自動移除觀察者 |
3. 觀察 LiveData 變化的條件
? 能觀察到變化的條件:
- 必須使用同一個 ViewModel 實例(通過相同的 ViewModelStoreOwner 獲?。?/li>
- 必須在該 ViewModel 實例上調(diào)用
setValue()或postValue() - 必須在該 ViewModel 實例上調(diào)用
observe()注冊觀察者 - 觀察者綁定的 LifecycleOwner 必須處于活躍狀態(tài)(STARTED 或 RESUMED)
? 無法觀察到變化的情況:
- 使用不同的 ViewModelStoreOwner 獲取 ViewModel(不同的 ViewModel 實例)
- 在錯誤的 ViewModel 實例上設置值
- 未調(diào)用
observe()注冊觀察者 - 觀察者綁定的 LifecycleOwner 處于非活躍狀態(tài)
4. 測試場景分組說明
| 場景組 | setValue 來源 | Activity 是否 observe | 測試目的 |
|---|---|---|---|
| 場景1-3 | Activity 的 viewModel | ? 未 observe | 測試 Activity 設置值,F(xiàn)ragment 觀察的情況 |
| 場景4-5 | Fragment1 的 viewModel | ? observe | 測試 Fragment 設置值,Activity 和 Fragment 觀察的情況 |
四、最佳實踐建議
1. 共享數(shù)據(jù)場景
推薦配置:
- Activity 和需要共享數(shù)據(jù)的 Fragment 都使用 Activity 作為 ViewModelStoreOwner
- 使用 Activity 或 Fragment 作為 LifecycleOwner 都可以(取決于業(yè)務需求)
// Activity
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
viewModel.data.observe(this) { ... }
// Fragment
viewModel = ViewModelProvider(requireActivity()).get(MyViewModel::class.java)
viewModel.data.observe(this) { ... } // 或 observe(requireActivity()) { ... }
2. 獨立數(shù)據(jù)場景
推薦配置:
- 每個 Fragment 使用 Fragment 自身 作為 ViewModelStoreOwner
- 使用 Fragment 自身 作為 LifecycleOwner
// Fragment
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
viewModel.data.observe(this) { ... }
3. 注意事項
?? 避免的配置:
- Fragment 使用 Fragment 作為 ViewModelStoreOwner,但使用 Activity 作為 LifecycleOwner(容易造成混淆)
- 在 Activity 中設置值,但 Fragment 使用獨立的 ViewModel 實例(無法觀察到變化)
五、測試代碼示例
場景4 的完整實現(xiàn)(推薦配置)
// Activity
class TestLiveDataActivity : BaseActivity() {
private lateinit var viewModel: TestLiveDataViewModel
override fun initData() {
viewModel = ViewModelProvider(this).get(TestLiveDataViewModel::class.java)
viewModel.testLiveData.observe(this) { value ->
LogUtil.d("TestLiveData", "Activity觀察到: $value")
}
}
}
// Fragment1
class TestLiveDataFragment1 : BaseFragment() {
private lateinit var viewModel: TestLiveDataViewModel
override fun initData() {
viewModel = ViewModelProvider(requireActivity()).get(TestLiveDataViewModel::class.java)
viewModel.testLiveData.observe(this) { value ->
LogUtil.d("TestLiveData", "Fragment1觀察到: $value")
}
}
}
// Fragment2
class TestLiveDataFragment2 : BaseFragment() {
private lateinit var viewModel: TestLiveDataViewModel
override fun initData() {
viewModel = ViewModelProvider(this).get(TestLiveDataViewModel::class.java)
viewModel.testLiveData.observe(this) { value ->
LogUtil.d("TestLiveData", "Fragment2觀察到: $value")
}
}
}
六、總結
- ViewModelStoreOwner 決定數(shù)據(jù)共享:使用相同的 ViewModelStoreOwner 才能共享同一個 ViewModel 實例
- LifecycleOwner 決定生命周期綁定:觀察者會跟隨 LifecycleOwner 的生命周期自動管理
- 觀察變化的前提:必須在同一個 ViewModel 實例上設置值和觀察
- 推薦做法:需要共享數(shù)據(jù)時,Activity 和 Fragment 都使用 Activity 作為 ViewModelStoreOwner