Search code examples
androidandroid-fragmentskotlinandroid-dialogfragment

Dialog Fragment can't pass back events to calling Fragment in Android?


In my Android App, I have navigation drawer activity as the MainActivity. And I do not intend to do any tasks in the MainActivity other than navigation, I want to keep it simple and use Fragments for my tasks.

So I have a Fragment which calls a DialogFragment, the DialogFragment passes back events to the Fragment. My implementation is similar to the code given here in the docs.

But, my app crashes when the dialog is needed to appear.

This is my DialogFragment:

class DialogSubjectsProgress: DialogFragment() {
    internal lateinit var listener: TheDialogListener

    interface TheDialogListener {
        fun onDialogCancel(dialog: DialogFragment)
        fun onDialogDismiss(dialog: DialogFragment)
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as TheDialogListener
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        super.onCreateDialog(savedInstanceState)

        // show progress dialog
        val progressView = activity!!.layoutInflater.inflate(R.layout.dialog_progress_i, null)
        progressView.findViewById<TextView>(R.id.progress_message).text = "Fetching data"

        return activity!!.let {
            val progressBuilder = AlertDialog.Builder(it, R.style.ThemeOverlay_AppCompat_Dialog)
            progressBuilder
                .setView(progressView)
                .setOnCancelListener {
                    listener.onDialogCancel(this)
                }
                .setOnDismissListener {
                    listener.onDialogDismiss(this)
                }
                .create()
        }
    }
}

And this my Fragment code, which according to the docs is for an Activity:

class FragmentSubjects: Fragment(), DialogSubjectsProgress.TheDialogListener {

    // other code

    private fun addSubject() {
        // show progress dialog
        val progressDialog = DialogSubjectsProgress()
        progressDialog.show(activity!!.supportFragmentManager, "null")

        // todo
        // progressDialog.dismiss()

    }

    override fun onDialogCancel(dialog: DialogFragment) {
        // User canceled the dialog
    }

    override fun onDialogDismiss(dialog: DialogFragment) {
        // Dialog's work is done
        // todo
    }

}

I have found a solution to this here, but I don't really understand it because it is written in Java, and I don't understand Java. I need help in Kotlin!!

----edit----

This is the log:

java.lang.ClassCastException: com.example.kotlinappv3.MainActivity cannot be cast to com.example.kotlinappv3.DialogSubjectsProgress$TheDialogListener
        at com.example.kotlinappv3.DialogSubjectsProgress.onAttach(DialogSubjectsProgress.kt:27)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1404)
        at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1784)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManager.java:1852)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:802)
        at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManager.java:2625)
        at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2411)
        at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2366)
        at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2273)
        at androidx.fragment.app.FragmentManagerImpl$1.run(FragmentManager.java:733)
        at android.os.Handler.handleCallback(Handler.java:874)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:198)
        at android.app.ActivityThread.main(ActivityThread.java:6729)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

The line

at com.example.kotlinappv3.DialogSubjectsProgress.onAttach(DialogSubjectsProgress.kt:27)

is pointing to

listener = context as TheDialogListener

in my DialogFragment code.


Solution

  • in your addSubject method instead of

    activity!!.supportFragmentManager
    

    use:

    childFragmentManager
    

    and in DialogFragment code, change:

    override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as TheDialogListener
    }
    

    to:

    override fun onAttachFragment(childFragment: Fragment?) {
        super.onAttachFragment(childFragment)
        listener = context as TheDialogListener
    }