簡體   English   中英

當我從一個片段回到另一個片段時,我的觀察者總是開火

[英]My observer is always firing when I come back from one fragment to another

我正在使用導航組件,我有Fragment AFragment 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM