[英]My observer is always firing when I come back from one fragment to another
我正在使用導航組件,我有Fragment A和Fragment B ,我從Fragment A發送一個 object 到帶有安全參數的Fragment B並導航到它。
override fun onSelectableItemClick(position:Int,product:Product) {
val action = StoreFragmentDirections.actionNavigationStoreToOptionsSelectFragment(product,position)
findNavController().navigate(action)
}
現在,在我的Fragment B中進行一些邏輯處理后,我想再次將該數據傳遞給Fragment A ,我使用它
btn_add_to_cart.setOnClickListener {button ->
findNavController().previousBackStackEntry?.savedStateHandle?.set("optionList",Pair(result,product_position))
findNavController().popBackStack()
}
然后在Fragment A中,我用
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Pair<MutableList<ProductOptions>,Int>>("optionList")
?.observe(viewLifecycleOwner, Observer {
storeAdapter.updateProductOptions(it.second,it.first)
})
現在,這工作正常,但如果我 go 從片段 A到片段 B並按下后退按鈕,上面的觀察者再次觸發復制我當前的數據,有沒有辦法在我只按下btn_add_to_cart
按鈕時觸發這個觀察者片段 B ?
從您的代碼中不清楚您的最后一段代碼在哪里被調用 - 您在哪里將Observer添加到LiveData 。 我猜它在方法之一onResume()或onViewStateRestored()或任何其他生命周期回調中,每當您從Fragment B返回Fragment A時都會再次調用它。 如果是這種情況,那么您正在向 LiveData 添加一個新的觀察者,並且LiveData的任何觀察者都會收到當前值的即時更新。
將該段代碼移動到在片段的生命周期中僅調用一次的回調方法之一。
面臨同樣的問題
通過從
savedStateHandle
實時數據中刪除舊數據來解決此問題
內部片段 B:
button?.setOnClickListener {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, data)
findNavController().popBackStack()
}
內部片段 A:
這是使用實時數據刪除方法刪除舊數據的關鍵,它應該在創建視圖之后,如片段的onViewCreated方法
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>(key)?.observe(viewLifecycleOwner) {
result(it)
findNavController().currentBackStackEntry?.savedStateHandle?.remove<String>(key)
}
}
更新:
我為此創建了擴展以便更好地使用
fun <T> Fragment.setBackStackData(key: String, data: T, doBack: Boolean = false) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, data)
if (doBack)
findNavController().popBackStack()
}
fun <T> Fragment.getBackStackData(key: String, singleCall : Boolean= true , result: (T) -> (Unit)) {
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)
?.observe(viewLifecycleOwner) {
result(it)
//if not removed then when click back without set data it will return previous data
if(singleCall) findNavController().currentBackStackEntry?.savedStateHandle?.remove<T>(key)
}
}
在片段內調用就像
在片段 B 中設置數據時
var user : User = User(data) // Make sure this is parcelable or serializable
setBackStackData("key",user,true)
在片段 A 中獲取數據時
getBackStackData<User>("key",true) { it ->
}
感謝這個家伙
你使用這個擴展:
fun <T> Fragment.getResult(key: String = "key") =
findNavController().currentBackStackEntry?.savedStateHandle?.get<T>(key)
fun <T> Fragment.getResultLiveData(key: String = "key"): MutableLiveData<T>? {
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
findNavController().previousBackStackEntry?.savedStateHandle?.remove<T>(key)
}
})
return findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)
}
fun <T> Fragment.setResult(key: String = "key", result: T) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(key, result)
}
例子:
片段A -> 片段B
片段B需要設置TestModel.class的結果
結果TestModel.class
data class ResultTestModel(val id:String?, val name:String?)
片段 A:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// ...
getNavigationResultLiveData<PassengerFragmentResultNavigationModel>(
"UNIQUE_KEY")?.observe(viewLifecycleOwner) { result ->
Log.i("-->","${result.id} and ${result.name}")
}
//...
}
Fragment B:設置數據並調用popBackStack。
ResultTestModel(id = "xyz", name = "Rasoul")
setNavigationResult(key = "UNIQUE_KEY", result = resultNavigation)
findNavController().popBackStack()
您可以在MutableLiveData
MutableSharedFlow
請在此處查看答案
https://stackoverflow.com/a/66111168/8354145
在這種情況下,這個答案應該有所幫助。 使用單一直播事件。
否則在這些情況下,可能會使用共享視圖 model(可能會限制在導航圖中),但是您不需要使用savedStateHandle
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.