在Activity中綁定一個ViewModel,
Fragments間共用這個ViewModel,
使用Naviagtion來切換Fragment間的頁面時,
每次切換都會重走一次Fragment的生命週期,
也就是處於“STARTED 或 RESUMED 狀態”,
導致從其他頁面切換回來之後,
會觸發LiveData的數據回調(observer被觸發)。
在Activity中保存一個ViewModel,
使用Navigation和Fragment實現頁面的切換,
AFragment獲取Activity的ViewModel並註冊LiveData為observer,
此時使用setValue讓AFragment收到一次LiveData數據,
然後切換到BFragment(AFragment被銷毀),
之後切回AFragment,會發現重新註冊LiveData數據,
AFragment再次收到LiveData數據。

圖源:https://bbs.huaweicloud.com/blogs/detail/256402
新增一個Event class
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
用Event包裝你原本的data。
ViewModel層 val selectedDate: LiveData<Event<String?>>
get() = _selectedDate
private val _selectedDate = MutableLiveData<Event<String?>>()
fun setSelectedDate(date: String?) {
_selectedDate.value = Event(date)
}
Fragment層 viewModel.selectedDate.observe(viewLifecycleOwner, {
it.getContentIfNotHandled()?.apply { result ->
tv_selectedDate.text = result
}
})
透過getContentIfNotHandled取得Event中原本的LiveData,
能夠抓取正確值,
而不會一直被Fragment間切換影響而重複調用。
參考: