简体   繁体   中英

DialogFragment Listener

I have a DialogFragment with a listener for when a button gets clicked to call a function in my fragment.

I am getting lateinit property listener has not been initialized when I click the positive button.

DialogFragment

class CreateCollectionDialog: DialogFragment() {
    lateinit var listener: CreateCollectionDialogListener

    interface CreateCollectionDialogListener {
        fun onDialogPositiveClick(dialog: DialogFragment, collectionName: String)
        // fun onDialogNegativeClick(dialog: DialogFragment)
    }

    override fun onAttachFragment(childFragment: Fragment) {
        println("onAttachFragment")
        super.onAttachFragment(childFragment)
        listener = context as CreateCollectionDialogListener
        println(listener)
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)
            val inflater = requireActivity().layoutInflater
            builder.setView(inflater.inflate(R.layout.dialog_collection, null))
                .setPositiveButton("Create", DialogInterface.OnClickListener { dialog, id ->
                    // Create new collection
                    var newCollectionName = view?.findViewById<EditText>(R.id.newCollectionName)?.text.toString()
                    if (!newCollectionName.equals("") && newCollectionName != null) {
                        listener.onDialogPositiveClick(this, newCollectionName)
                    }
                })
                .setNegativeButton("Cancel", DialogInterface.OnClickListener { dialog, id ->
                    // User canceled dialog
                    // listener.onDialogNegativeClick(this)
                })
            builder.create()
        }?: throw IllegalStateException("Activity cannot be null")
    }

    override fun onStart() {
        super.onStart()
        val positive: Button = (dialog as AlertDialog?)!!.getButton(AlertDialog.BUTTON_POSITIVE)
        positive.setTextColor(resources.getColor(R.color.topColor))

        val negative: Button = (dialog as AlertDialog?)!!.getButton(AlertDialog.BUTTON_NEGATIVE)
        negative.setTextColor(Color.RED)
    }
}

Fragment

class CollectionsFragment: Fragment(), CreateCollectionDialog.CreateCollectionDialogListener {
     override fun onOptionsItemSelected(item: MenuItem): Boolean {

        when (item.itemId) {
            R.id.add -> {
                val createDialog = CreateCollectionDialog()
                createDialog.show(fragmentManager!!, "")
                return true
            }
        }
        return false
    }

    override fun onDialogPositiveClick(dialog: DialogFragment, collectionName: String) {
        addNewCollection(collectionName)
    }
}

onAttachFragment is called when a fragment is attached as a child of this fragment, which in this case, never and not required.

Use onAttach(Context context) for current scenario. Dialog fragment has no child so onAttachFragment will never be called.

To initialize the listener from the parent fragment, use:

// inside fragment lifecycle methods like onviewcreated etc
listener = getParentFragment() as CreateCollectionDialogListener

The simplest way to solve this problem would be to assign the listener at the time you create the dialog:

when (item.itemId) {
    R.id.add -> {
        val createDialog = CreateCollectionDialog()
        createDialog.listener = this
        createDialog.show(fragmentManager!!, "")
        return true
    }
}

However, note that this will have problems if the activity is destroyed and recreated due to a configuration change.

To solve that, I would leverage the concept of "target fragments":

when (item.itemId) {
    R.id.add -> {
        val createDialog = CreateCollectionDialog()
        createDialog.setTargetFragment(this, 0)
        createDialog.show(fragmentManager!!, "")
        return true
    }
}

And now, in your other fragment, instead of having a listener field, you can just cast the targetFragment property:

if (!newCollectionName.equals("") && newCollectionName != null) {
    val listener = targetFragment as CreateCollectionDialogListener
    listener.onDialogPositiveClick(this, newCollectionName)
}

Problem seems to be with your fragmentManager.! Try using childFragmentManager to open the DialogFragment.

Also, check if lateinit listener is actually initialized or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM