1

I am using Kotlin and fragments in my app. I created a secondary constructor to keep primary constructor empty in order to avoid the error of could not find fragment constructor. I assigned late initialize variable in secondary constructor of fragment but it is null when called, causing null pointer exception. Here is the code sequence:

class VideoFragment(
) : Fragment(),
VideoFileListener {

private lateinit var mainContext: Context
private lateinit var itemClickListener: ItemClickListener

constructor(
    mainContext: Context,
    itemClickListener: ItemClickListener
) : this() {
    this.mainContext = mainContext
    this.itemClickListener = itemClickListener
}
}

companion object {
    @JvmStatic
    fun newInstance(
        mainContext: Context,
        itemClickListener: ItemClickListener
    ) =
        VideoFragment(mainContext, itemClickListener)
}

I access my fragment with static newInstance function. Why these variables are not initialized in secondary constructor?

Junaid Khan
  • 315
  • 5
  • 16

1 Answers1

2

You kind of miss the point of the newInstance static method here. The whole point of that method is to put the given parameters supplied there into the fragment arguments, so the fragment can later retrieve those parameters from it's arguments. This is necessary because on configuration change your Fragment will be recreated using the no-arg constructor, and then you'll have someplace to restore the original arguments for your Fragment. Have a look at this answer for further explanation and example: https://stackoverflow.com/a/9245510/5601663

This has another effect. You can't really have callbacks as Fragment arguments, because these arguments need to be Serializable or Parcelable. I highly recommend you watch this video from the point I linked, it elaborates further on this: https://youtu.be/dcYKW48tHQ4?t=1867

One last thing, if you got NullPointerException then it's cause by something other then your lateinit property not being initialized, because that would produce an error similar to this: kotlin.UninitializedPropertyAccessException: lateinit property foo has not been initialized.

A. Patrik
  • 1,530
  • 9
  • 20
  • You are right, I encountered this error: kotlin.UninitializedPropertyAccessException: lateinit property foo has not been initialized? Is there any proper sloution for it? – Junaid Khan Dec 01 '20 at 13:52
  • I will be very thankful to you if you please write a simple code to put callbacks as arguments – Junaid Khan Dec 01 '20 at 13:57
  • The short answer is that you can't put callbacks inside fragment arguments. What you can do instead is to implement `ItemClickListener` inside your activity, and then use `requireActivity() as ItemClickListener`, or use an activity scoped `ViewModel` – A. Patrik Dec 01 '20 at 14:04
  • Ok, I already implemented ItemClickListener in MainAActivity, but where I will use this line, requireActivity() as ItemClickListener? – Junaid Khan Dec 01 '20 at 14:09
  • Where you tried to use your original `lateinit` property, so instead of calling `itemClickListener.itemClicked(...)` you should call `(requireActivity() as ItemClickListener).itemClicked(...)` – A. Patrik Dec 01 '20 at 14:11
  • requireActivity(), How to access this in recycler view adapter? – Junaid Khan Dec 01 '20 at 14:42
  • In am calling itemClickListener.itemClicked(...) in my recycler view adapter – Junaid Khan Dec 01 '20 at 14:42
  • The typical pattern for callbacks used by fragment classes in Jetpack, and suggested in some of the examples in documentation, is to define an interface in the Fragment, have the Activity class itself implement that interface, and in the Fragment, safe-cast the Activity to that interface to use it. (I cringe just describing it, but there are a lot of things to cringe about in the design of the Android framework.) – Tenfour04 Dec 01 '20 at 14:57
  • The RecyclerView adapter shouldn't need to know about the fragment or activity if you want to encapsulate it. It can define its own listener for its clickable items and let the fragment pass a listener to it to be called by the item click listeners. – Tenfour04 Dec 01 '20 at 15:00