使用导航组件在任何目的地弹出常见错误对话框的最佳实践

The best practice to pop up a common error dialog in any destination with navigation component

我想在任何目标片段的 ViewModel 中收到错误时显示错误对话框。

现在,我创建了一个 BaseViewModel 和一个 BaseFragment 来完成这些工作,并使所有 fragmentsViewModels 扩展它。
但是很难将所有目的地都连接到对话框的 DialogFragment。

我应该将对话框从 nav_graph.xml 中删除吗?

如果您使用的是 kotlin,则可以使用扩展函数来实现

inline fun Activity.alertDialog(
    title: CharSequence? = null,
    message: CharSequence? = null,
    func: AlertDialogHelper.() -> Unit
) {
    val dialogFragment = AlertDialogHelper(this, title, message).apply {
        func()
    }
    val fragmentTransaction = (this as AppCompatActivity).supportFragmentManager.beginTransaction()
    fragmentTransaction.let { dialogFragment.show(it, TAG) }
}

inline fun Fragment.alertDialog(
    title: CharSequence? = null,
    message: CharSequence? = null,
    func: AlertDialogHelper.() -> Unit
) {
    val dialogFragment = AlertDialogHelper(this.context!!, title, message).apply {
        func()
    }
    val fragmentTransaction = (this).childFragmentManager.beginTransaction()
    fragmentTransaction.let { dialogFragment.show(it, TAG) }
}

AlertDialogHelper 是由 DialogFragment

扩展的同一个对话框 class

A​​lertDialogHelper

    class AlertDialogHelper(context: Context, title: CharSequence?, message: CharSequence?) :
    DialogFragment() {

    private val dialogView: View by lazyFast {
        LayoutInflater.from(context).inflate(R.layout.dialog_layout, null)
    }

    private val title: TextView by lazyFast {
        dialogView.findViewById(R.id.dialogInfoTitleTextView)
    }

    private val message: TextView by lazyFast {
        dialogView.findViewById(R.id.dialogInfoMessageTextView)
    }

    private val positiveButton: Button by lazyFast {
        dialogView.findViewById(R.id.dialogInfoPositiveButton)
    }

    private val negativeButton: Button by lazyFast {
        dialogView.findViewById(R.id.dialogInfoNegativeButton)
    }

    var cancelable: Boolean? = true

    init {
        this.title.text = title
        this.message.text = message
    }


    fun positiveButton(text: CharSequence, func: (() -> Unit)? = null) {
        with(positiveButton) {
            this.text = text
            setClickListenerToDialogButton(func)
        }
    }


    fun negativeButton(text: CharSequence, func: (() -> Unit)? = null) {
        with(negativeButton) {
            this.text = text
            setClickListenerToDialogButton(func)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return dialogView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        title.goneIfTextEmpty()
        message.goneIfTextEmpty()
        positiveButton.goneIfTextEmpty()
        negativeButton.goneIfTextEmpty()

        dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        isCancelable = this.cancelable!!
    }

    override fun onDestroyView() {
        super.onDestroyView()
    }

    private fun TextView.goneIfTextEmpty() {
        visibility = if (text.isNullOrEmpty()) {
            View.GONE
        } else {
            View.VISIBLE
        }
    }

    private fun Button.setClickListenerToDialogButton(func: (() -> Unit)?) {
        setOnClickListener {
            func?.invoke()
            dialog?.dismiss()
        }
    }

    fun <T> lazyFast(operation: () -> T): Lazy<T> = lazy(LazyThreadSafetyMode.NONE) {
        operation()
    }
}