Reputation: 1739
I know there is a lateinit
or lazy
keyword in Kotlin to prevent indiscriminate initialization and thus minimize wasted resources.
I wanted to use the lazy keyword to use findViewById
when necessary events occur.
However, if I use the lazy keyword, nothing happens. It doesn't even cause an error.
Conversely, when findViewId
is normally used in onCreateView
, click event occurs normally.
Why doesn't lazy work?
class BodyPartDialogFragment : DialogFragment(), View.OnClickListener{
private val ll: LinearLayout? by lazy { view?.findViewById(R.id.ll_body_part) }
// private lateinit var button: Button
private val button: Button? by lazy { view?.findViewById(R.id.start) }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_body_part_dialog, container, false)
// ll = view.findViewById(R.id.ll_body_part)
// button = view.findViewById(R.id.start)
ll?.apply { clipToOutline = true }
button?.setOnClickListener { // Nothing Happened
Toast.makeText(context, "Noting Selected", Toast.LENGTH_SHORT).show()
}
return view
}
Upvotes: 0
Views: 1558
Reputation: 41
You can do this to get access to View in the future using 'by lazy'
private val previewImage by lazy { requireActivity().findViewById<ImageView>(R.id.ivImage) }
Then you can use it like
previewImage.setImageURI(imageUri)
Upvotes: 0
Reputation: 152847
getView()
that is behind the view
property returns whatever you returned from onCreateView()
. When you access view
inside onCreateView()
, it hasn't yet returned anything and hence a null
is returned, and your ?.
safecall becomes a no-op.
You can use a lazy
approach like this after onCreateView()
, such as in onViewCreated()
.
Upvotes: 1
Reputation: 1001
view
(or really getView()
) is the view that is returned from onCreateView()
. You're trying to access that before you have returned from onCreateView()
so it returns null, and your lazy value is then also null. You can make this work by accessing it later, ie. in onViewCreated()
class BodyPartDialogFragment : DialogFragment(), View.OnClickListener{
private val ll: LinearLayout? by lazy { view?.findViewById(R.id.ll_body_part) }
// private lateinit var button: Button
private val button: Button? by lazy { view?.findViewById(R.id.start) }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_body_part_dialog, container, false)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
ll?.apply { clipToOutline = true }
button?.setOnClickListener { // Nothing Happened
Toast.makeText(context, "Noting Selected", Toast.LENGTH_SHORT).show()
}
}
}
This is more clear if you use requireView()
since it returns a non-null View
and rather throws an exception, so your app would have crashed with the error message did not return a View from onCreateView() or this was called before onCreateView()
.
Upvotes: 0
Reputation: 198143
It looks like you may be initializing things in the wrong order.
Consider that renaming a local variable always preserves semantics, so let's modify your code a little:
private val ll: LinearLayout? by lazy { view?.findViewById(R.id.ll_body_part) }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val someRandomView: View = inflater.inflate(R.layout.fragment_body_part_dialog, container, false)
ll?.apply { clipToOutline = true }
button?.setOnClickListener { // Nothing Happened
Toast.makeText(context, "Noting Selected", Toast.LENGTH_SHORT).show()
}
return someRandomView
}
Do you see the issue? ll
is being initialized with a view
that hasn't been assigned yet in onCreateView
.
Upvotes: 0