How to create variable in Kotlin without initialization? - android

This is simple question. In Java you can create String variable or couple of variables without adding any value to it. This is used at start of the class before onCreate() is called in Activity. I've used lateinit property in Kotlin to achieve that, but now I have a problem with changing visibility of RecyclerView. It will throw exception "lateinit property recyclerView has not been initialized".
Is there any way how to know if property is initialized? This is called at start of the parent activity in Fragment (hide recyclerView and show ProgressBar till data are binded to recyclerView).

In Java you can create String variable or couple of variables without adding any value to it
Actually in that case it is implicitly declared null. Kotlin does not do that, because of its nullability mechanism. You must explicitly declare a variable nullable to allow null:
var str: String // does not work
var str: String? // does not work
var str: String? = null // works
Also see this answer.
Your other option indeed is to mark it lateinit:
lateinit var str: String // works
If you need to make a check to see if it is initialized before using it, you use
if (::str.isInitialized)
But really you should avoid this check and just make sure it is initialized before using it.

If you need to get your UI element in Kotlin, you do not need to create variable and initialise it by using findViewById anymore (though you can). Use kotlin view binding, which works pretty well.
https://kotlinlang.org/docs/tutorials/android-plugin.html#view-binding

Related

Why we can't declare variable as "var" for lazy initialization [duplicate]

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.

Android Kotlin: Smart cast to 'TextView' is impossible, because 'x' is a property that has open or custom getter

I use findViewById to get references to views in a custom DialogClass outside the view hierarchy. Since I want these references throughout the dialog class, and since they are not available until the call to setContentView, I use lazy field initialization in the dialog class definition:
private val balanceView : TextView? by lazy { dialog?.findViewById(R.id.balanceTextView)}
Later, in a separate function that runs after the call to setContentView, I have two commands related to balanceView:
private fun setupBalance(){
balanceView!!.visibility = View.VISIBLE
balanceView.text = presentation.balance
}
I expected the second command to compile since we are ensuring balanceView is not null in the first command. However, the compiler underlines the second command with this message:
Smart cast to 'TextView' is impossible, because 'balanceView' is a property that has open or custom getter
I was wondering how to interpret this message - to my knowledge the lazy keyword doesn't make a variable open.
The use of a property delegate like lazy means it has a custom getter. A custom getter prevents the compiler from being able to ensure that the value returned by the property will be the same in your two consecutive calls, so it cannot smart-cast.
Since balanceView is nullable, you shouldn't be using !! either, or your app will crash when balanceView is null. The correct way to write your function (if you don't know if balanceView is currently null) would be like this:
private fun setupBalance(){
balanceView?.apply {
visibility = View.VISIBLE
text = presentation.balance
}
}
If there's no chance of it being null, don't use a nullable property, and then you won't have to worry about null-safe calls and smart-casting. But you seem to also have a nullable dialog that it is dependent on. I don't know what's going on higher-up-stream, so I can't help with that.

Nullable var with `?` vs. lateinit var

What is the best way to define global variables in a Kotlin/Android activity/fragment?
What are the different scenarios when you should use these 2 methods for defining a global variable:
var viewpager: CustomViewPager? = null
or
lateinit var viewpager: CustomViewPager
?
If I use the former, I won't have to check for null in my code. For example if I used lateinit for the following:
viewpager = activity?.findViewById<CustomViewPager>(R.id.viewpager) then I would have to check for null.
using lateinit, you are saying that you absolutely will make sure that an instance of that variable is created somewhere (otherwise, your application will throw an exception if a lateinit has not been initialized) and then that variable also will not be null throughout the rest of your project, compared to using null, it means that this object potentially could be null somewhere in your code for the rest of the project and you will have to deal with nullability throughout.
If you are positive that you are not going to make a variable null and you require an instance of it always, use lateinit
Ask yourself this question :
Am I 100% sure that I will be using an instance of this variable somewhere in this class ?
If the answer to that is Yes, you should probably be using lateinit, as lateinit forces you to create an instance of it.
If the answer is No, you should probably be using a nullable field instead.
Taken from here : https://www.kotlindevelopment.com/lateinit-kotlin/
The lateinit keyword stands for late initialization. Lateinit comes very handy when a non-null initializer cannot be supplied in the constructor, but the developer is certain that the variable will not be null when accessing it, thus avoiding null checks when referencing it later.
i would recommend using the first method, it's better cause it eliminates app crashes if the code is trying to access the viewPager while it was not initialized, you can also use this in order to access the viewPager in the first method to make sure your app won't crash
viewPager?.let{"it"
}
this will create an instance of the viewPager if it was already initialized and use it as a val instead of a var, the instance is called "it" and u can rename it as anything by doing this after the first {
viewPager?.let{viewPager ->
}
If you make sure that variable will never be null in any place of the code then use lateinit. Here you have to initialize it before using it (in your case you can initialize it inside onCreate(..). Make sure that the variable will never become null later ELSE a null pointer exception will be fired.
In this way, you can directly use the variable without checking it if it's null or not.
Also, you can detect if the variable has initialized or not using:
if (:: viewpager.isInitialized) { .... }
On the other hand, you should use the nullable option using ?
In this case, you should check the variable before using it if it's null or not.
you can use ?. for that. You also can combine that with let for example:
viewPager?.let {
....
}

findViewById in kotlin unable to compile

New to Kotlin.
I am trying to create a activity with a member variable holding button object, but compiler gives me error when I try to do findViewById
I tried two ways for doing this but none works.
Note: I am not using Android extension
When you declare your property like this:
var btn = null
... its type gets inferred to Nothing?, which makes it so that nothing other than null can ever be assigned to it. What you should do instead is the following:
var btn: Button? = null
You might also want to look into declaring your Views in different ways.

How to cast view elements in kotlin? [duplicate]

I'm trying to build android application using Kotlin for the first time.
I want to declare on some buttons outside the OnCreate method and i can initialize them only Inside this function with findViewById.
Can i declare in simple and clean code like in java?
private Button btnProceed;
Because when converting it to Kotlin it look like:
private var btnProceed: Button? = null
And then when initialize OnClick function need to add ! sign:
btnProceed!!.setOnClickListener
What is the right and cleanest way?
This is a good use case for lateinit. Marking a property lateinit allows you to make it non nullable, but not assign it a value at the time that your Activity's constructor is called. It's there precisely for classes like Activities, when initialization happens in a separate initializer method, later than the constructor being run (in this case, onCreate).
private lateinit var btnProceed: Button
If the property is read before a real value is assigned to it, it will throw an exception at runtime - by using lateinit, you're taking the responsibility for initializing it before you access it for the first time.
Otherwise, if you want the compiler to guarantee safe access for you, you can make the Button nullable as the converter does by default. Instead of the unsafe !! operator though, which the converter often uses, you should use the safe call operator where you access the property:
btnProceed?.setOnClickListener { ... }
This will make a regular call if btnProceed is a non-null value, and do nothing otherwise.
On a final note, you can check out Kotlin Android Extensions, which eliminates the need to create properties for your Views altogether, if it works for your project.
Last edit (for now): you should also look at using lazy as described in the other answers. Being lazy is cool.
Instead of using lateinit, you can also do lazy initialization:
private val button by lazy {
findViewById(R.id.button) as Button
}
The first time you access the button property, it will execute the block once and use the result for future calls. In onCreate for example, you can now directly access it:
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(bundle)
setContentView(R.layout.my_view)
button.setOnClickListener { ... }
}
You can do it with lateinit as #zsmb13 suggest BUT this has the disadvantage that your views will be variable instead of final. If you want them to be final you can use the lazy property delegation
By using lazy you can declare how the value will be initialized when you first try to access it so by declaring
private val btnProceed: Button by lazy {
findViewById(R.id.yourID)
}
Whenever you access your btnProceed you will have your activity (this example assume you're using an activity) loaded so you can use that method

Categories

Resources