Search code examples
androidkotlin

How to open DialogFragment from Fragment with callback?


I want to open my dialogfragment class from a fragment and want to return the data from the dialog fragment. I am a uni student and had an example app where it was done from the main activity with a callback implementation but when I try to open the dialog from a fragment it still directs it to the main activity not the fragment I opened it from. Can I do this with the callback implementation or do I have to do something else?

I have code from the example project which works when it is launched from the main activity. I searched for it online and found that it can be done with navigation arguments too but wanted to do this way if possible. If not I would appreciate what do I have to change to do with the navigation arguments because I didn't quite understand it.

class MenuFragment : Fragment(), PlanAdapter.PlanItemClickListener, PlanItemDialogFragment.NewPlanItemDialogListener {
    private lateinit var binding : FragmentMenuBinding

    private lateinit var database: PlanListDatabase
    private lateinit var adapter: PlanAdapter

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentMenuBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        database = PlanListDatabase.getDatabase(requireActivity().applicationContext)

        binding.fab.setOnClickListener{
            PlanItemDialogFragment().show(
                childFragmentManager,
                PlanItemDialogFragment.TAG
            )
        }
    }

class PlanItemDialogFragment : DialogFragment() {
    interface NewPlanItemDialogListener {
        fun onPlanItemCreated(newItem: PlanItem)
    }

    private lateinit var listener: NewPlanItemDialogListener

    private lateinit var binding: DialogNewItemBinding

    override fun onAttach(context: Context) {
        super.onAttach(context)
        listener = context as? NewPlanItemDialogListener
            ?: throw RuntimeException("Activity must implement the NewPlanItemDialogListener interface!")
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        binding = DialogNewItemBinding.inflate(LayoutInflater.from(context))

        return AlertDialog.Builder(requireContext())
            .setTitle(hu.bme.aut.android.mobil_hf.R.string.new_plan_item)
            .setView(binding.root)
            .setPositiveButton(hu.bme.aut.android.mobil_hf.R.string.button_ok) { dialogInterface, i ->
                if (isValid()) {
                    listener.onPlanItemCreated(getPlanItem())
                }
            }
            .setNegativeButton(hu.bme.aut.android.mobil_hf.R.string.button_cancel, null)
            .create()
    }

Solution

  • The result is being directed to the main activity instead of the fragment it was opened from because the context used in this scenario is the activity's context.

    You can use lamda function instead of callback to retrive the data from Dialog,

        class PlanItemDialogFragment(private val onPlantCreated:(PlanItem)-> Unit):DialogFragment(){
    
        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
            return AlertDialog.Builder(requireContext())
                .setTitle("Title")
                .setMessage("Message...")
                .setPositiveButton("Ok"){ dialogInterface, i ->
    
                    onPlantCreated(getPlantItem()) 
    
                }
                .setNegativeButton("Cancel"){ dialogInterface, i ->
    
                }
                .create()
        }
    

    }

    Then call dialog in fragment.

    fab.setOnClickListener {
            PlanItemDialogFragment(
                onPlantCreated = { planItem ->
                    // Use the 'planItem' data here
                }
            ).show(childFragmentManager,PlanItemDialogFragment.TAG)
        }