Search code examples
androidkotlinandroid-alertdialoganko

Is there any way to use Kotlin Anko Alertdialog with handling screen rotation changes?


Using Anko library is pretty easy, but when i rotate screen, my dialog dismisses. The only way how to avoid this is to use child of DialogFragment() with method show(fm, TAG).

So we need to override method onCreateDialog(savedInstanceState: Bundle?): Dialog which returns Dialog instance. But Anko's alert{ }.build() returns DialogInterface instance

So, is there any way to use anko in this situation?

alert {
        message = "Message"                   
        positiveButton("OK") {
            //stuff
        }
        negativeButton("NOT OK") {
            //stuff
        }
}.show()

EDIT

So, that what I did. I've created abstract BaseDialogFragment:

abstract class BaseDialogFragment : DialogFragment() {

    abstract val ankoAlert: AlertBuilder<DialogInterface>

    protected var dialogListener: DialogListener? = null

    protected val vm by lazy {
        act.getViewModel(DialogViewModel::class)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        dialogListener = parentFragment as? DialogListener
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
            (ankoAlert.build() as? Dialog)
                    ?: error("Anko DialogInterface is no longer backed by Android Dialog")
}

Then I've created some dialogs, like that:

class MyDialogFragment : BaseDialogFragment() {

    companion object {
        fun create() = MyDialogFragment ()
    }

    override val ankoAlert: AlertBuilder<DialogInterface>
        get() = alert {
            negativeButton(R.string.app_canceled) {
                dialogListener?.onDismiss?.invoke()
            }
            customView = createCustomView(vm.data)
        }

    fun createCustomView(data: Data): View {
        //returning view
    }
}

Also my DialogListener is sort of that:

interface DialogListener {

    var onDismiss: () -> Unit

    val onClick: (Data) -> Unit

    var onPostClick: (Data) -> Unit

}

And finally, in parent fragment we can use:

MyDialogFragment.create().show(childFragmentManager, MyDialogFragment::class.java.simpleName)

Hope it will help somebody.


Solution

  • From the Android Documentation, Dialog implements DialogInterface. So all known subclasses of Dialog including AlertDialog implement that interface.

    You can cast and return the result from the build as follows:

    return alert {
        message = "Message"                   
        positiveButton("OK") {
            //stuff
        }
        negativeButton("NOT OK") {
            //stuff
        }
    }.build() as Dialog
    

    This will work but if Anko ever changes its implementation you will get a ClassCastException. To get a cleaner error you can use the following.

    val dialogInterface = alert {
        message = "Message"                   
        positiveButton("OK") {
            //stuff
        }
        negativeButton("NOT OK") {
            //stuff
        }
    }.build()
    return (dialogInterface as? Dialog) ?: error("Anko DialogInterface is no longer backed by Android Dialog")
    

    This gives you a more explicit error, but most likely won't be needed.