我想做的是在LiveData观察器中使用Navigation控制器,因此,当用户单击列表中的项目时,它会通知ViewModel,然后ViewModel更新数据,并且在发生这种情况时,片段会观察到此情况并导航到下一个。
我的问题是,由于某种原因,观察者被调用两次,而第二次,我收到一个异常,指出该NavController不知道目的地。
点击我的片段
override fun onClick(view: View?) {
viewModel.productSelected.observe(viewLifecycleOwner, Observer<ProductModel> {
try {
this.navigationController.navigate(R.id.action_product_list_to_product_detail)
} catch (e: IllegalArgumentException) { }
})
val itemPosition = view?.let { recyclerView.getChildLayoutPosition(it) }
viewModel.onProductSelected(listWithHeaders[itemPosition!!].id)
}
在我的ViewModel中:
fun onProductSelected(productId: String) {
productSelected.value = getProductById(productId)
}
答案 0 :(得分:1)
之所以调用它两次,是因为首先订阅,然后返回默认值,然后在productSelected LiveData
中更改一个值,这样观察者就会再次收到通知。
因此,开始观察 之后onProductSelected
如下:
override fun onClick(view: View?) {
val itemPosition = view?.let { recyclerView.getChildLayoutPosition(it) }
viewModel.onProductSelected(listWithHeaders[itemPosition!!].id)
viewModel.productSelected.observe(viewLifecycleOwner, Observer<ProductModel> {
try {
this.navigationController.navigate(R.id.action_product_list_to_product_detail)
} catch (e: IllegalArgumentException) { }
})
}
再次提醒您,一旦您开始观察LiveData
,则每次productSelected
更改时都会收到通知。是你想要的吗?如果没有,那么一旦使用过的观察者就应该删除。
答案 1 :(得分:1)
捕获异常可能有用,但是它也会使您错过其他一些问题。最好与目标位置一起检查当前布局,以验证用户是否已经在该位置。我更喜欢的另一种选择是检查先前的目的地,例如:
fun Fragment.currentDestination() = findNavController().currentDestination
fun Fragment.previousDestination() = findNavController().previousBackStackEntry?.destination
fun NavDestination.getDestinationIdFromAction(@IdRes actionId: Int) = getAction(actionId)?.destinationId
private fun Fragment.isAlreadyAtDestination(@IdRes actionId: Int): Boolean {
val previousDestinationId = previousDestination()?.getDestinationIdFromAction(actionId)
val currentDestinationId = currentDestination()?.id
return previousDestinationId == currentDestinationId
}
fun Fragment.navigate(directions: NavDirections) {
if (!isAlreadyAtDestination(directions.actionId)) {
findNavController().navigate(directions)
}
}
基本上,这里我们验证我们还没有到达目的地。这可以通过将先前的操作目标与当前目标进行比较来完成。让我知道代码是否有帮助!