androidandroid-fragmentsmaterial-designandroid-fragmentactivity

Getting an error when launching a material date picker from a fragment android


I'm trying to launch an Material date picker from a fragment and I'm getting this error

java.lang.IllegalStateException: Fragment MaterialDatePicker{6058a76} (da2fbbc0-ee9f-4536-85f7-3942c18a1087) not attached to an activity.

My Fragment

@AndroidEntryPoint
class ReportFragment : Fragment() {

    private var _binding: FragmentReportBinding? = null
    private val binding get() = _binding!!

    private var stDate: Long? = null
    private var ndDate: Long? = null

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentReportBinding.inflate(inflater, container, false)
    
        setUpUi()

        return binding.root
    }
   
    private fun setUpUi() {
        with(binding) {
            startDate.setOnClickListener {
                showDatePicker(
                    getString(R.string.select_start_date),
                    selectedStartDate,
                    DateType.START_DATE
                )
            }
        }
     }

      private fun showDatePicker(dateCategory: String, textView: TextView, dateType: DateType) {
        val datePicker = MaterialDatePicker.Builder.datePicker().apply {
            setTitleText(dateCategory)
            setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
            setSelection(MaterialDatePicker.todayInUtcMilliseconds())
        }.build()
        datePicker.apply {
            show(requireActivity().supportFragmentManager, "DATE_PICKER")
            addOnPositiveButtonClickListener {
                val date = this.headerText
                textView.text = date
                when (dateType) {
                    DateType.START_DATE -> stDate = it
                    DateType.END_DATE -> ndDate = it
                }
            }
        }
    }
}

enum class DateType {
    START_DATE,
    END_DATE
}

This is the error I'm getting

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.reachafrika.reachafrikapay, PID: 15162
    java.lang.IllegalStateException: Fragment MaterialDatePicker{6058a76} (da2fbbc0-ee9f-4536-85f7-3942c18a1087) not attached to an activity.
        at androidx.fragment.app.Fragment.requireActivity(Fragment.java:928)
        at com.reachafrika.reachafrikapay.presentation.ui.fragments.reports.ReportFragment.showDatePicker(ReportFragment.kt:137)
        at com.reachafrika.reachafrikapay.presentation.ui.fragments.reports.ReportFragment.setUpUi$lambda-4$lambda-1(ReportFragment.kt:71)
        at com.reachafrika.reachafrikapay.presentation.ui.fragments.reports.ReportFragment.$r8$lambda$5X7432cB-iIkf15NUD-AuzGqT3E(Unknown Source:0)
        at com.reachafrika.reachafrikapay.presentation.ui.fragments.reports.ReportFragment$$ExternalSyntheticLambda3.onClick(Unknown Source:4)
        at android.view.View.performClick(View.java:7184)
        at android.view.View.performClickInternal(View.java:7157)
        at android.view.View.access$3500(View.java:821)
        at android.view.View$PerformClick.run(View.java:27660)
        at android.os.Handler.handleCallback(Handler.java:914)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:225)
        at android.app.ActivityThread.main(ActivityThread.java:7563)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:994)

Solution

  • I replaced the

    datePicker.apply {
            show(requireActivity() ...
    

    with the following code

                show(this@ReportFragment.requireActivity().supportFragmentManager, "DATE_PICKER")
    

    and it worked

    Here is the full body function

     private fun showDatePicker(dateCategory: String, textView: TextView, dateType: DateType) {
            val datePicker = MaterialDatePicker.Builder.datePicker().apply {
                setTitleText(dateCategory)
                setInputMode(MaterialDatePicker.INPUT_MODE_CALENDAR)
                setSelection(MaterialDatePicker.todayInUtcMilliseconds())
            }.build()
            datePicker.apply {
                show(this@ReportFragment.requireActivity().supportFragmentManager, "DATE_PICKER")
                addOnPositiveButtonClickListener {
                    val date = this.headerText
                    textView.text = date
                    when (dateType) {
                        DateType.START_DATE -> stDate = it
                        DateType.END_DATE -> ndDate = it
                    }
                }
            }
        }
    

    As the suggestion was given above. that apply changes the receiver i.e. this, and the receiver here has requireActivity() defined too, so it resolves first.