我有一个简单的项目来测试Navigation
与DialogFragment
目的地如何工作:
一切正常, ,如果我尝试快速连续打开/关闭对话框。如果点击得足够快,我会得到一个
IllegalArgumentException:导航目标 NavController未知com.example.app:id/show_dialog
很明显,这是一个极端情况,因为大多数用户除非尝试测试应用程序的完整性,否则不会快速重复按下按钮。
无论如何,要解决此问题,我添加了一项检查以确保当前目的地是包含show_dialog
操作的目的地。
val currentDest = findNavController().currentDestination?.id
if (currentDest == R.id.fragment_dest) {
findNavController().navigate(TestFragmentDirections.showDialog())
}
进行此更改似乎已消除了该问题。无论我按下按钮有多快,我都无法重现该错误。到目前为止,这已经足够了,但是我想知道其背后的原因。
我的问题:
在这种情况下,为什么必须用条件语句包装
navigate
调用?
我的猜测是,它与1)观察者模式或2)与创建/显示对话框相关的滞后有关。或两者结合。
无论如何,这里是相关代码:
TestFragment.kt
class TestFragment : Fragment() {
private lateinit var binding: TestFragmentBinding
private lateinit var viewModel: TestViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = TestFragmentBinding.inflate(inflater, container, false)
viewModel = ViewModelProviders.of(this).get(TestViewModel::class.java)
binding.lifecycleOwner = this
binding.viewModel = viewModel
viewModel.eventShowDialog.observe(this, Observer { showDialog ->
if (showDialog) {
/**
* Error occurs here without the if statement
*/
val currentDest = findNavController().currentDestination?.id
if (currentDest == R.id.fragment_dest) {
findNavController().navigate(TestFragmentDirections.showDialog())
}
viewModel.onShowDialogComplete()
}
})
return binding.root
}
}
TestViewModel.kt
class TestViewModel : ViewModel() {
private val _eventShowDialog = MutableLiveData<Boolean>()
val eventShowDialog: LiveData<Boolean>
get() = _eventShowDialog
fun onShowDialog() {
_eventShowDialog.value = true
}
fun onShowDialogComplete() {
_eventShowDialog.value = false
}
}
dialog_nav.xml
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/dialog_nav"
app:startDestination="@id/fragment_dest">
<fragment
android:id="@+id/fragment_dest"
android:name="com.example.app.TestFragment"
android:label="Fragment">
<action
android:id="@+id/show_dialog"
app:destination="@id/dialog_dest"/>
</fragment>
<dialog
android:id="@+id/dialog_dest"
android:name="com.example.app.TestDialogFragment"
android:label="Dialog"/>
</navigation>
fragment_test.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.example.app.TestViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/dialog_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Show Dialog"
android:onClick="@{() -> viewModel.onShowDialog()}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
还有一张很好的图片。快速连续点击“显示对话框”按钮会产生错误。
答案 0 :(得分:1)
Your question is just based on the Android inside Architecture and is also dependent on the hardware performance. Just wrap it in a try/catch
block:
try{
findNavController().navigate(TestFragmentDirections.showDialog())
}catch(e: IllegalArgumentException){
e.printStackTrace
}
答案 1 :(得分:0)
您可能会得到IllegalArgumentException,因为如果看到showDialog()方法,则会发现实现如下:
public void show(FragmentManager manager, String tag) {
mDismissed = false;
mShownByMe = true;
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
我建议您编写具有以下实现方式的showDialog
方法:
fragmentManager.beginTransaction()
.add(dialog, "TAG")
.commitAllowingStateLoss();