Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do I send my date from datepickerfragment to another fragment

I am new to android development. learning through big nerd ranch android 4e book this is an example from there, methods in the book are depreciated, so how do I sent data of date to another fragment

They are using targetfragment technique which is depreciated, so I am now stuck at this problem

This is my datepickerfragment.kt file:

private const val ARG_DATE = "date"
private const val RESULT_DATE_KEY = "resultDate"
private const val ARG_REQUEST_CODE = "requestCode"

class DatePickerFragment : DialogFragment() {

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

       val dateListener = DatePickerDialog.OnDateSetListener { _: DatePicker, year: Int, month: Int, day: Int ->
           val resultDate: Date = GregorianCalendar(year, month, day).time

           val result = Bundle().apply {
               putSerializable(RESULT_DATE_KEY, resultDate)

           }

           val resultRequestCode = requireArguments().getString(ARG_REQUEST_CODE, "")
       }


       val date = arguments?.getSerializable(ARG_DATE) as Date
       val calendar = Calendar.getInstance()
       calendar.time = date
       val initialYear = calendar.get(Calendar.YEAR)
       val initialMonth = calendar.get(Calendar.MONTH)
       val initialDay = calendar.get(Calendar.DAY_OF_MONTH)

       return DatePickerDialog(
               requireContext(),
               dateListener,
               initialYear,
               initialMonth,
               initialDay
       )
   }

   interface Callbacks {
       fun onDateSelected(date: Date)
   }


   companion object {

       fun getSelectedDate(result: Bundle) = result.getSerializable(RESULT_DATE_KEY) as Date

       fun newInstance(date: Date, requestCode: String): DatePickerFragment {
           val args = Bundle().apply {
               putSerializable(ARG_DATE, date)
               putString(ARG_REQUEST_CODE, requestCode)
           }

           return DatePickerFragment().apply {
               arguments = args
           }

       }
   }

}

This is my crimefragment.kt class:

private const val ARG_CRIME_ID = "crime_id"
private const val TAG = "CrimeFragment"
private const val REQUEST_DATE = "DialogDate"

class CrimeFragment : Fragment(), DatePickerFragment.Callbacks, FragmentResultListener {

    private lateinit var crime: Crime
    private lateinit var titleField: EditText
    private lateinit var dateButton: Button
    private lateinit var solvedCheckBox: CheckBox

    private val crimeDetailViewModel: CrimeDetailViewModel by lazy {
        ViewModelProvider(this).get(CrimeDetailViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        crime = Crime()
        val crimeId: UUID = arguments?.getSerializable(ARG_CRIME_ID) as UUID
        Log.d(TAG, "args bundle crime Id:$crimeId")

        crimeDetailViewModel.loadCrime(crimeId)
    }

    override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_crime, container, false)


        titleField = view.findViewById(R.id.crime_title) as EditText
        solvedCheckBox = view.findViewById(R.id.crime_solved1) as CheckBox
        dateButton = view.findViewById(R.id.crime_date)

        return view

    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        crimeDetailViewModel.crimeLiveData.observe(
                viewLifecycleOwner,
                Observer { crime ->
                    crime?.let {
                        this.crime = crime
                        updateUI()
                    }

                }
        )
        childFragmentManager.setFragmentResultListener(REQUEST_DATE, viewLifecycleOwner, this)


    }


    override fun onStart() {
        super.onStart()

        val titleWatcher = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                crime.title = s.toString()
            }

            override fun afterTextChanged(s: Editable?) {

            }

        }
        titleField.addTextChangedListener(titleWatcher)

        dateButton.setOnClickListener {
            DatePickerFragment
                    .newInstance(crime.date, REQUEST_DATE)
                    .show(childFragmentManager, REQUEST_DATE)


        }

        solvedCheckBox.apply {
            setOnCheckedChangeListener { _, isChecked ->
                crime.isSolved = isChecked
            }
        }
    }

    private fun updateUI() {
        titleField.setText(crime.title)
        dateButton.text = crime.date.toString()
        solvedCheckBox.apply {
            isChecked = crime.isSolved
            jumpDrawablesToCurrentState()

        }
    }

    companion object {
        fun newInstance(crimeId: UUID): CrimeFragment {
            val args = Bundle().apply {
                putSerializable(ARG_CRIME_ID, crimeId)

            }
            return CrimeFragment().apply { arguments = args }
        }
    }

    override fun onStop() {
        super.onStop()
        crimeDetailViewModel.saveCrime(crime)
    }

    override fun onDateSelected(date: Date) {
        crime.date = date
    }

    override fun onFragmentResult(requestCode: String, result: Bundle) {
        when (requestCode) {
            REQUEST_DATE -> {
                Log.d(TAG, "received result for $requestCode")
                crime.date = DatePickerFragment.getSelectedDate(result)
                updateUI()
            }
        }
    }


}
like image 624
Jaydip Solanki Avatar asked Sep 07 '25 00:09

Jaydip Solanki


1 Answers

You seem to be using Fragment Result API, which requires two steps. first you setFragmentResultListener in the fragment where you want to receive result (CrimeFragment in your case), second you call setFragmentResult from the fragment that produces the result. You are missing the second step. to solve this, update OnDateSetListener as

val dateListener = DatePickerDialog.OnDateSetListener { _: DatePicker, year: Int, month: Int, day: Int ->
    val resultDate: Date = GregorianCalendar(year, month, day).time
    val result = Bundle().apply {
        putSerializable("DATE", resultDate)
    }
    // Set the fragment result, this will invoke the `onFragmentResult` of CrimeFragment
    parentFragmentManager.setFragmentResult("requestKey", result)
}

Now in CrimeFragment register FragmentResultListener as

// use same value of requestKey as specified in setFragmentResult
childFragmentManager.setFragmentResultListener("requestKey", viewLifecycleOwner, this)

Now update onFragmentResult to

override fun onFragmentResult(requestKey: String, result: Bundle) {
     when(requestKey){
        "requestKey" -> {
            // get date from the result bundle
            val date = result.getString("DATE")
            // do something with date
        }
    }
}

Apart from this there is another approach that you can take, which is to use a shared ViewModel, since both the fragments share the activity, you can get the ViewModel associated with activity.

get ViewModel in CrimeFragment and DatePickerFragment as

// Get view model associated with activity
private val crimeDetailViewModel: CrimeDetailViewModel by activityViewModels()

Now in OnDateSetListener of DatePickerFragment simply store the date in some ViewModel property

crimeDetailViewModel.date = // updated date from OnDateSetListener

after this you can access the crimeDetailViewModel.date inside CrimeFragment

like image 136
mightyWOZ Avatar answered Sep 08 '25 21:09

mightyWOZ