"lateinit" or "by lazy" when defining global android.widget var/val
Asked Answered
F

2

9

When defining a global android.widget variable, e.g. TextView, is it preferable to use lateinit or by lazy? I initially thought using by lazy would be preferred as its immutable but I'm not entirely sure.

by lazy example:

class MainActivity: AppCompatActivity() {

    val helloWorldTextView by lazy { findViewById(R.id.helloWorldTextView) as TextView }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        updateTextView(helloWorldTextView)
    }

    fun updateTextView(tv: TextView?) {
        tv?.setText("Hello?")
    }
}

lateinit example:

class MainActivity: AppCompatActivity() {

    lateinit var helloWorldTextView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        helloWorldTextView = findViewById(R.id.helloWorldTextView) as TextView
        updateTextView(helloWorldTextView)
    }

    fun updateTextView(tv: TextView?) {
        tv?.setText("Hello?")
    }
}

Are there any benefits of using one over the other when defining a global android.widget var/val? Are there any pitfalls with using by lazy to define a android.widget val? Is the decision just based on whether you want a mutable or immutable value?

Fetial answered 18/5, 2017 at 20:12 Comment(0)
S
11

There's one pitfall with by lazy. The widget property would be read-only and therefore technically final (in Java terms). But there's no documented guarantee that onCreate() is called only once for an instance. Also findViewById() could return null.

So using lateinit is preferable and you'll get an exception to tell you if the val was used before onCreate().

A third possibility would be Android synthetic properties. Then you don't need to worry about the variables at all.

import kotlinx.android.synthetic.main.activity_main.*

helloWorldTextView.text = "Hello?"
Syzran answered 18/5, 2017 at 21:8 Comment(4)
These are great points. Also, wow! That extension is amazing. Thank you for including it in your answer.Fetial
onCreate(…) is indeed called once per Activity instance, but the lazy delegate isn't tied to it anyway, it's just initialized when first called, which is perfectly ok in this case. Of course, synthetic properties are easier anywayForwardness
lazy can also cause a memory leak in Fragments bignerdranch.com/blog/kotlin-when-to-use-lazy-or-lateinitFalstaffian
Late note: lazy delegate is a separate object which holds a noinline initializer lambda object and a lock object inside. It also involves some synchronization. Thus, by lazy is the most heavyweight option ever. But it's 2022 so everyone who still uses XML chooses viewBinding.Alit
T
0

Here are some key differences between lateinit & by lazy

  • var is always used with lateinit.when you declare any variable with keyword lateinit then memory is allocated to that variable at the time of declaration
  • val is used with by lazy which mean that a varable who is declared by lazy keyword will allocate memory when it will be used in oncreate()
Tallula answered 2/3, 2023 at 11:16 Comment(1)
This is wrong. Memory is allocated for all the “variables” (actually backing member fields) of a class when it is first instantiated, regardless of whether they use lateinit or by lazy or neither. In the case of by lazy a Lazy instance is also instantiated at that time.Amplify

© 2022 - 2024 — McMap. All rights reserved.