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()
}
}
}
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With