While exploring some repositories on GitHub I found some people define fields twice for example
private var _binding: FragmentBinding? = null
private val binding: FragmentBinding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentBinding.inflate(layoutInflater)
return binding.root
}
why do some developers do this and why not just define the field once
private var binding: FragmentBinding? = null
In this particular context this is done to avoid any memory leaks. Fragments outlive their view,which means any reference to the view must be set to null when view is destroyed. so to take care of the memory leak the reference to the binding object is set to null in onDestroyView. in your case onDestroyView should look as
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
so this takes care of the memory leak issue, but now there is another problem, every time you use the _binding to access some view, you need to use (!!) non-null assertion as _binding!!.myView.setOnClickListener etc.
In order to avoid this redundant use of (!!), there is another property binding, which is not null. so now you can simply write binding.myView.setOnClickListener.
The comments and other answer talking about you missing the concept are talking about a different concept than what you are asking about in your example code.
The concept they're talking about is using a more restrictive publicly exposed version of a property. Like making the public version of a MutableList exposed only as a read-only List. This is a good practice for encapsulation, but it is not what your example code is doing, although both involve using a backing property with an _ prefix.
Your example is with two private properties with the same type. This is done for Android view binding in a Fragment because it needs to be possible to set the property to null when the Fragment is detached, so the bound views are not leaked. But it is inconvenient to have to keep dealing with a nullable property in the Fragment code, since most of your uses of the binding will be in functions that are only called while the Fragment is attached and the binding reference is not null.
This code allows a backing nullable _binding property that stores the actual reference to the binding and can be set to null when the fragment is detached. The binding property has no backing field, so it cannot cause the views to be leaked, but you can use it as a non-null property, which is safe so long as you only call it while the Fragment is attached. It is similar to requireContext() and requireActivity(), which are conveniently non-null, but are only safe to use while the Fragment is attached.
I think you misunderstood the concept here!
It's paradigm in general programming that keep one private member field with the _ prefix while exposing another variable with the same name as public member of the class without _ prefix.
I.e. let's say you have an interface or an abstract class called "Foo" and it's inheritance/child class as "Bar".
interface Foo {}
class Bar : Foo
While using it's functionality into some other class (let's say 'Baz') you found out that creating object of "Bar" is good enough for you on this particular "Baz" class.
class Baz {
var bar: Bar? = null
}
But, at the same time you also want your caller/consumer of "Baz" class not to have access to this var bar: Bar? = null in such a way that it's immutable since it's internal variable used on "Baz".
This is the moment, where this paradigm comes into picture where you expose your bar as read only variable while reassigning/modifying it internally n number of times as well as of the type of it's parent to limit it's scope. something like below:
class Baz {
private var _bar: Bar? = null
val bar: Foo get() = _bar // Here we expose private variable _bar as Foo type only on getter as well
}
Side note: (This happens in Kotlin, because it provides default getters & setters and providing getter only on public one restricts it's usage to read-only outside the class/object)
Source - Kotlin Docs
These are called backing properties in kotlin.
Advantages of using a backing properties.
The variable with prefix _ will be private var.
var - So it is mutable.
private - So it can only be mutated in the same class, but it is not exposed to other files.
The other variable will be public val.
public - So it is accessible from any file.
val - It can only be read. Writing to val is restricted.
If the data has to changes from other classes, we can use a public method to do so. The advantages of using a method rather than the default constructor is we can add any custom validation logic we want before updating the private variable.
Related
I was following the google codelab. There I came across the following code:
class Calculator: Fragment() {
private var _binding: FragmentCalculatorBinding? = null
private val binding get() = _binding!!
}
What is the need for the get()?
We can do this in the following way:
class Calculator: Fragment() {
private var _binding: FragmentCalculatorBinding? = null
private val binding = _binding!!
}
The explaination given there was:
Here, get() means this property is "get-only". That means you can get the value, but once assigned (as it is here), you can't assign it to something else.
but I don't understand it. Please help me with this.
The whole point in having a second property here is to allow the first property to be set back to null. (The second property is for convenience and should only be used when the fragment is known to be attached to an Activity.) Using a getter means it does the evaluation _binding!! each time it is accessed. Without get() it evaluates it once when the class is instantiated and assigns the result to a backing field. Since _binding is null at class instantiation time, this would be guaranteed to fail. And even if it didn’t fail, it would have an outdated reference if the fragment got detached and reattached.
Your description of what “get only” means is inverted. Either the code lab got their explanation backwards or you paraphrased it backwards.
In this case, you don't. It's very messy in my opinion.
Simply use:
private lateinit var binding: FragmentCalculatorBinding
It's does the same thing as your existing code - throws exception if you use the variable before instantiate it.
Keep in mind that you must instantiate it before using it (the whole point of lateinit var).
If you use it like this, you have a very explicit way of setting binding - you have to do it using _binding (which would probably just happen once in onCreateView(). For all the places where you actually use it, you would use binding, which both checks if _banding has actually been set, and cannot accidentally be changed as it is immutable, thereby saving you from potential bugs.
That being said - I would probably go with a lateinit var as well, and lose all the null checking, but that is a matter of personal taste I think.
using get() after the variable name makes it assign to the value when we each time trying to access this variable
as mentioned above without get() the variable will be assigned immediately when this class instantiated
I was declared a binding object in a fragment as lateinit var binding: EditInsuranceDialogBinding but a colleague said "This is a bad practice and Binding object should be Optional . "
So in the declaration will be instead like this: var binding: EditInsuranceDialogBinding? = null, initialised in the onCreateContentView and make it null in the onDestroyView
I want to know what is the best to choose the type of Binding (optional or not)? and does lateinit cost a lot in the compiler and memory ? When we should NOT choose lateinit and when we should use it?
but a colleague said "This is a bad practice and Binding object should be Optional . "
It is possible that your colleague really meant that the binding object should be wrapped in Optional.
I want to know what is the best to choose the type of Binding (optional or not)?
lateinit var is not evil. However, it is not ideal for all circumstances.
In this case, a binding object has a specific lifecycle, and we need to stop using it after onDestroyView(). If you declare the property as:
private lateinit var binding: EditInsuranceDialogBinding
...then you have no way of setting it to something after onDestroyView() that says "we do not have a valid binding". It is easy to wind up having code in a fragment that runs after onDestroyView(), and that code needs to know that it is not safe to use the binding. There is no way to create an EditInsuranceDialogBinding instance that represents the "not safe to use the binding" state.
The alternative that you chose is reasonable:
private var binding: EditInsuranceDialogBinding? = null
...where you set binding to null in onDestroyView().
You could also go with:
private var binding: Optional<EditInsuranceDialogBinding> = Optional.empty()
...where you set binding back to Optional.empty() in onDestroyView(). There are also custom binding delegates, such as this one, that you could use.
and does lateinit cost a lot in the compiler and memory ?
No.
When we should NOT choose lateinit and when we should use it?
I try to only use lateinit when I am very certain that I will initialize it before use.
This one is not bad approach. We use lateinit when we guarantee the initialization before using it. lateinit doesn't allocate the memory until it is initialized.
It is initialized only once. Next time when you use it, you get the value from memory where it is used for the first time.
This question already has answers here:
Property initialization using "by lazy" vs. "lateinit"
(9 answers)
Closed 2 years ago.
I have been using both of them, both of them provide safety for NullPointerException but the lateinit can cause UnInitializedPropetyException, So which of these two is safer. What is the best use case for each of them, when the lateinit best fits and when lazy best fits?
The point I am trying to make based on
Safety //lateinit saves from NPE but yet it can throw UnInitializedPropetyException
Optimality
Is not it better to go for lazy, when one does not really need mutable property?
What is the usefulness of lateinit?
when lateinit var abc:Def can give UnInitializedPropetyException and
var abc:Def?=null can give NPE, in both cases we have mutability and exception.
They have two different purposes:
by lazy is for initialising something only if it is accessed runtime at some point. Consider a costly/resource intensive component or initialisation. If this component is used only in certain cases, by lazy can help with avoiding these costly initialisations
lateinit is more of a convenience method if you can't initialise something right away. For ex. in android if you want to save out a reference to one of your views, you can only initialise them in your onCreateView/onViewCreated. Unfortunately lateinit works with vars only, so it doesn't enforce immutability, so use it with caution :)
Update:
Both with lateinit and with the nullability pattern you get mutability & unsafety, so in this sense they are not so different.
But lateinit is a lot more verbose in the sense that you know if something goes wrong it's an initialisation problem (or it should be).
The nullability pattern is okay for more general problems, for ex: if you plan on clearing/resetting a component
lazy is safest because you need assign a value to it first and don't worry about initial state. Beside, about the resource, when first use lazy object, it is initialized. About performance, the result is saved in memory when you call get() first and then each get() call give result from memory.
About best case use them late init and lazy
late init use in case you not sure about the way which object is
initialized and mutability
lazy use in case, you want only instance object exist in class
scope and immutability
When to use which one?
lateinit can only be used with var (mutable)properties whereas lazy can only be used for val (immutable)properties.
lateinit don’t work with primitive type.
While using Singleton Pattern (Object Declaration in Kotlin) we should use lazy, as it will be initialized upon first use.
In lateinit the type of the property must be non-null.
lateinit can only be used when the property does not have a custom getter or setter.
In lateinit var, it depends on the user to initialize the property properly in multi-threaded environments. Initialization by lazy { … } is thread-safe by default and make sure initialization is done at most once.
var — Declared as mutable
val — Read-only (immutable)
val someText: String by lazy { "Variable is lazy initialized" }
fun doPrintSomeText() {
println("Length is " + someText.length) // someText will be initialized here
}
lateinit var someText: String // initialize laterfun doPrintSomeText() {
someText = "Variable is lateinit" // initialize
println("Length is " + someText.length)
}
You can check if lateinit var is initialized or not before using it
lateinit var foo: Foo
if(::foo.isInitialized) {
// foo is initialized. Go Ahead
}
When you know the var will be needed but not at the time of class loading, then You can declare it with lateinit. This means You will initialize it as per your need.
By lazy indicates that the variable is going to be initialized at the time of its first usage. And If you do not need to use that variable then it will not initialize at all.
And this will not result in NPE in any way.
In short, If we declare it as lateinit, then its tottally our duty as a developer to initialize it before using it
In Kotlin, if you don't want to initialize a class property inside the constructor or in the top of the class body, you have basically these two options (from the language reference):
Lazy Initialization
lazy() is a function that takes a lambda and returns an instance of Lazy<T> which can serve as a delegate for implementing a lazy property: the first call to get() executes the lambda passed to lazy() and remembers the result, subsequent calls to get() simply return the remembered result.
Example
public class Hello {
val myLazyString: String by lazy { "Hello" }
}
So, the first call and the subsequential calls, wherever it is, to myLazyString will return Hello
Late Initialization
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.
To handle this case, you can mark the property with the lateinit modifier:
public class MyTest {
lateinit var subject: TestSubject
#SetUp fun setup() { subject = TestSubject() }
#Test fun test() { subject.method() }
}
The modifier can only be used on var properties declared inside the body of a class (not in the primary constructor), and only when the property does not have a custom getter or setter. The type of the property must be non-null, and it must not be a primitive type.
So, how to choose correctly between these two options, since both of them can solve the same problem?
Here are the significant differences between lateinit var and by lazy { ... } delegated property:
lazy { ... } delegate can only be used for val properties, whereas lateinit can only be applied to vars, because it can't be compiled to a final field, thus no immutability can be guaranteed;
lateinit var has a backing field which stores the value, and by lazy { ... } creates a delegate object in which the value is stored once calculated, stores the reference to the delegate instance in the class object and generates the getter for the property that works with the delegate instance. So if you need the backing field present in the class, use lateinit;
In addition to vals, lateinit cannot be used for nullable properties or Java primitive types (this is because of null used for uninitialized value);
lateinit var can be initialized from anywhere the object is seen from, e.g. from inside a framework code, and multiple initialization scenarios are possible for different objects of a single class. by lazy { ... }, in turn, defines the only initializer for the property, which can be altered only by overriding the property in a subclass. If you want your property to be initialized from outside in a way probably unknown beforehand, use lateinit.
Initialization by lazy { ... } is thread-safe by default and guarantees that the initializer is invoked at most once (but this can be altered by using another lazy overload). In the case of lateinit var, it's up to the user's code to initialize the property correctly in multi-threaded environments.
A Lazy instance can be saved, passed around and even used for multiple properties. On contrary, lateinit vars do not store any additional runtime state (only null in the field for uninitialized value).
If you hold a reference to an instance of Lazy, isInitialized() allows you to check whether it has already been initialized (and you can obtain such instance with reflection from a delegated property). To check whether a lateinit property has been initialized, you can use property::isInitialized since Kotlin 1.2.
A lambda passed to by lazy { ... } may capture references from the context where it is used into its closure.. It will then store the references and release them only once the property has been initialized. This may lead to object hierarchies, such as Android activities, not being released for too long (or ever, if the property remains accessible and is never accessed), so you should be careful about what you use inside the initializer lambda.
Also, there's another way not mentioned in the question: Delegates.notNull(), which is suitable for deferred initialization of non-null properties, including those of Java primitive types.
lateinit vs lazy
lateinit
i) Use it with mutable variable[var]
lateinit var name: String //Allowed
lateinit val name: String //Not Allowed
ii) Allowed with only non-nullable data types
lateinit var name: String //Allowed
lateinit var name: String? //Not Allowed
iii) It is a promise to compiler that the value will be initialized in future.
NOTE: If you try to access lateinit variable without initializing it then it throws UnInitializedPropertyAccessException.
lazy
i) Lazy initialization was designed to prevent unnecessary initialization of objects.
ii) Your property will not be initialized unless you use it.
iii) It is initialized only once. Next time when you use it, you get the value from cache memory.
iv) It is thread safe(It is initialized in the thread where it is used for the first time. Other threads use the same value stored in the cache).
v) The property can only be val.
vi) The property can be of any type (including primitives and nullables, which are not allowed with lateinit).
Very Short and concise Answer
lateinit: It initialize non-null properties lately
Unlike lazy initialization, lateinit allows the compiler to recognize that the value of the non-null property is not stored in the constructor stage to compile normally.
lazy Initialization
by lazy may be very useful when implementing read-only(val) properties that perform lazy-initialization in Kotlin.
by lazy { ... } performs its initializer where the defined property is first used, not its declaration.
Additionnally to hotkey's good answer, here is how I choose among the two in practice:
lateinit is for external initialisation: when you need external stuff to initialise your value by calling a method.
e.g. by calling:
private lateinit var value: MyClass
fun init(externalProperties: Any) {
value = somethingThatDependsOn(externalProperties)
}
While lazy is when it only uses dependencies internal to your object.
In addition to all of the great answers, there is a concept called lazy loading:
Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed.
Using it properly, you can reduce the loading time of your application. And Kotlin way of it's implementation is by lazy() which loads the needed value to your variable whenever it's needed.
But lateinit is used when you are sure a variable won't be null or empty and will be initialized before you use it -e.g. in onResume() method for android- and so you don't want to declare it as a nullable type.
Everything is correct above, but one of facts simple explanation LAZY----There are cases when you want to delay the creation of an instance of your object until its
first usage. This technique is known as lazy initialization or lazy instantiation. The main
purpose of lazy initialization is to boost performance and reduce your memory footprint. If
instantiating an instance of your type carries a large computational cost and the program
might end up not actually using it, you would want to delay or even avoid wasting CPU
cycles.
Diff btw lateinit and lazy
lateinit
Use only with mutable variable i.e. var and non-nullable data types
lateinit var name: String //Allowed with non-nullable
You are telling the compiler that the value will be initialized in future.
NOTE: If you try to access lateinit variable without initializing it then it throws UnInitializedPropertyAccessException.
lazy
Lazy initialization was designed to prevent unnecessary initialization of objects.
Your variable will not be initialized unless you use it.
It is initialized only once. Next time when you use it, you get the value from cache memory.
It is thread safe.
The variable can only be val and non-nullable.
Cheers :)
If you are using Spring container and you want to initialize non-nullable bean field, lateinit is better suited.
#Autowired
lateinit var myBean: MyBean
If you use an unchangable variable, then it is better to initialize with by lazy { ... } or val. In this case you can be sure that it will always be initialized when needed and at most 1 time.
If you want a non-null variable, that can change it's value, use lateinit var. In Android development you can later initialize it in such events like onCreate, onResume. Be aware, that if you call REST request and access this variable, it may lead to an exception UninitializedPropertyAccessException: lateinit property yourVariable has not been initialized, because the request can execute faster than that variable could initialize.
One of the benefits of using Kotlin is its Null safety. However when I have been programming Android Apps using it, I have found myself needing to use null. When declaring my UI elements such as TextViews and Buttons etc. I need to create private variables that are initialised to each object during the onCreate, but this means i need to explicitly allow null on each reference. This kind of defeats one of the purposes of using Kotlin. Is there a better solution, to creating instances of UI Objects within my activities in Android.
This is how I am doing it, at this moment.
var messageView: TextView? = null
var firstNameView: EditText? = null
var lastNameView: EditText? = null
var ageView: EditText? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
messageView = findViewById<TextView>(R.id.message)
firstNameView = findViewById<EditText>(R.id.firstName)
lastNameView = findViewById<EditText>(R.id.lastName)
ageView = findViewById<EditText>(R.id.age)
findViewById<Button>(R.id.showMessage).setOnClickListener(this)
findViewById<Button>(R.id.update).setOnClickListener(this)
}
Try defining these as lateinit, it should get you past the need to have them nullable if you can guarantee that you'll provide values before they are read.
lateinit var messageView: TextView
lateinit var firstNameView: EditText
lateinit var lastNameView: EditText
lateinit var ageView: EditText
From the documentation for lateinit:
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.