当我从一个片段回到另一个片段时,我的观察者总是在开火

时间:2020-06-10 19:38:32

标签: android android-fragments kotlin android-viewmodel android-architecture-navigation

我正在使用导航组件,我有片段A 片段B ,来自片段A ,我将对象发送到片段B 带有安全参数,然后导航到它。

override fun onSelectableItemClick(position:Int,product:Product) {
        val action = StoreFragmentDirections.actionNavigationStoreToOptionsSelectFragment(product,position)
        findNavController().navigate(action)
    }

现在,在我的片段B 中经过逻辑处理后,我想再次将数据传送到片段A ,我将使用

  btn_add_to_cart.setOnClickListener {button ->     
 findNavController().previousBackStackEntry?.savedStateHandle?.set("optionList",Pair(result,product_position))
                findNavController().popBackStack()
            }

然后在片段A 中,我用

捕获了这些数据
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Pair<MutableList<ProductOptions>,Int>>("optionList")
            ?.observe(viewLifecycleOwner, Observer {
                storeAdapter.updateProductOptions(it.second,it.first)
            })

现在,这工作正常,但是如果我从片段A 转到片段B ,然后按返回按钮,上方的观察者将再次触发复制我的当前数据,当我只按 B片段中的btn_add_to_cart按钮时,有什么方法可以解雇该观察者吗?

2 个答案:

答案 0 :(得分:0)

不清楚您的代码在哪里调用了最后一段代码-在 LiveData 中添加了观察者。我猜想它在方法 onResume() onViewStateRestored()或任何其他生命周期回调中,每当您返回到 Fragment A < / strong>来自片段B 。如果是这种情况,那么您将向 LiveData 添加一个新的观察者,并且LiveData的任何观察者都会收到当前值的即时更新。

将这段代码移动到其中一个片段的生命周期中仅被调用一次的回调方法中。

答案 1 :(得分:0)

面临同样的问题

<块引用>

通过从 savedStateHandle 实时数据中删除旧数据来解决此问题

在片段 B 中:

      button?.setOnClickListener {

        findNavController().previousBackStackEntry?.savedStateHandle?.set(key, data)
        findNavController().popBackStack()

     }

在片段 A 中:

<块引用>

这里是使用实时数据删除旧数据的关键remove方法,它应该在创建视图之后,就像片段的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)
            }
    }

在fragment里面调用就像

同时在片段 B 中设置数据

   var user : User = User(data) // Make sure this is parcelable or serializable   
   setBackStackData("key",user,true)

在片段 A 中获取数据时

getBackStackData<User>("key",true) { it ->

}

感谢This Guy