В вашем дизайне есть недостаток, который не имеет ничего общего даже с DI или Dagger: ваш класс DialogUtils
будет использовать простые AlertDialog
s вместо DialogFragment
s. Это означает, что диалоги, сгенерированные вашим классом, не являются постоянными на экране (например, во время перезапуска активности, например, когда устройство вращается), что дает плохой пользовательский опыт.
Так что вместо этого я бы написал пользовательскийAlertDialogFragment
реализация, которая взаимодействует через обратные вызовы со своим хостом (который может быть Activity
или Fragment
), что означает, что ваша реализация фрагмента диалога ищет в определенных местах, если она находит хост, который реализует свой обратный вызов и передает ответные действия пользователя(например, нажатия кнопок и т. д.). Это некоторый служебный код, который я обычно использую в своих проектах для этой цели:
inline fun <reified T> Fragment.requireCallback(): T =
findCallback() ?: error("No parent / target found or parent / target does not implement " + T::class.java)
inline fun <reified T> Fragment.findCallback(): T? {
val callback: Any? = parentFragment ?: targetFragment ?: context
return callback as? T
}
Это может войти в вашу реализацию AlertDialogFragment
следующим образом:
class AlertDialogFragment : DialogFragment() {
private lateinit var listener: Listener
interface Listener {
fun onDialogResult(requestCode: Int, result: AlertDialogResult)
}
override fun onAttach(context: Context) {
super.onAttach(context)
listener = requireCallback()
}
...
}
Теперь, когда вы создаете свой экземплярв диалоге вашего родителя Activity
или Fragment
, вам просто нужно позволить этому родителю реализовать интерфейс AlertDialogFragment.Listener
, и вы перенаправите его результаты на ваш ViewModel
- и это хорошо: это будет работать при перезапуске активности!
Вы можете задаться вопросом, хотите ли вы требовать, чтобы обратный вызов был реализован на хосте для каждого диалога;Мое личное правило: для однокнопочных диалогов, которые в основном подтверждают действия (например, диалоговые окна с сообщениями об ошибках), я не требую наличия обратного вызова (т. е. используйте простой findCallback()
), в то время как для специальных реализаций DecisionDialogFragment
, которые имеют болееДля нажатия одной кнопки я обычно выполняю обратный вызов, поэтому мое приложение на самом деле падает, если обратный вызов не реализован на хосте, так как это обычно означает отсутствие фрагмента кода на моей стороне.