当前位置: 首页 > 知识库问答 >
问题:

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

麻书
2023-03-14

我正在使用导航组件,我有片段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\u add\u to\u cart按钮时,有没有办法只激发这个观察者?

共有3个答案

东方化
2023-03-14

从您的代码中不清楚您的最后一段代码在哪里被调用——您在哪里向LiveData添加了一个观察者。我猜想它在onResume()或onViewStateRestored()方法之一或任何其他生命周期回调中,每当您从片段B返回片段A时,都会再次调用该回调。如果是这样,那么您将向LiveData添加一个新的观察者,并且LiveData的任何观察者都会收到当前值的即时更新。

将这段代码移动到回调方法之一,该方法在片段的生命周期中只调用一次。

宋臻
2023-03-14

面临同样的问题

通过从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 ->

}

多亏了这个家伙

古棋
2023-03-14

您使用此扩展:

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需要设置TestModel的结果。班

结果模型。班

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}")
    }

    //...
}

片段B:设置数据并调用popBackStack。

ResultTestModel(id = "xyz", name = "Rasoul")
setNavigationResult(key = "UNIQUE_KEY", result = resultNavigation)
findNavController().popBackStack()
 类似资料:
  • 当我将一个片段(它是带有背景的全屏)显示在另一个片段(我们称之为main)上时,我的main片段仍然会对单击做出反应(即使我们没有看到按钮,我们也可以单击它)。 问题:如何防止点击第一(主)片段?

  • 我读过很多关于这方面的文章,但也有2012年或更早的文章。 (我只是打算从数据库中读取和插入一些数据。)

  • 我想创建一个类,它的功能只是做一个碎片事务,但我有一个错误。我的课是下一个: 进程:net.elinformaticoenganchado.sergio.crossfights,PID:5116 java.lang.runtimeException:无法启动活动ComponentInfo{net.elinformaticoenganchado.sergio.crossfights/net.elin

  • 先生/女士,我想使用android JAVA将一个片段回调到另一个片段。我试图找到问题,但没有找到解决方案。若我使用接口,它会向活动发送回调响应,这是我不想要的。非常感谢。

  • 每当一个片段显示给用户时,我需要执行一些代码。 通过查看API,我能看到的最接近的钩子方法是onResume。但是,从我的代码调试来看,当用户选择back-button返回到先前显示的片段时,似乎没有调用onResume。 为了澄清我看到的行为: 我有一个“parent”活动,它在ActionBar中配置选项卡...和2个片段F1和F2。 用户选择一个选项卡,F1被加载到活动中。按下按钮,用户就可