I am writing a Kotlin application, I've been studying this language for a little bit and I noticed that to create a variable you have to explicitly define if it can be null and then you use the ? operator.
Now, my question. Sometimes I have to define a global variable (a Fragment in this case), so I need to make it null, because I cannot initialize it yet
In java I don't have this problem because the first thing I do after declaring it is initializing in the onCreate() like this
TurboFragment fragment = null;
#Override
public void onCreate(Bundle savedInstanceState) {
...
fragment = adapter.getCurrentFragment();
}
And then I can use it without syntax problems
In Kotlin is different, because I have to do like that
private var fragment: TurboFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
fragment = adapter!!.currentFragment
fragment!!.foo()
var x = fragment!!.sampleInt
}
Now, every time I call an instance of fragment i have to use the null-safe !! operator. This makes my code a mess, because for every line I have at least one !! operator and it looks really unclear if it's so frequent, especially if you have 5 or more variables like that.
Is there a way to simplify the code or the nature of this language is like that?
Consider using Late-Initialized Properties. They're intended for your use-case.
private lateinit var fragment: TurboFragment
However, you should keep in mind that accessing a lateinit property before it has been initialized throws an exception. That means you should use them only if you are absolutely sure, they will be initialized.
print(fragment) // UninitializedPropertyAccessException is thrown
Related
I have a singleton class as follows
object SharedPrefTask {
fun doSomeWork() {
....
....
}}
I am using the method doSomeWork in 2 ways.
Approach 1
private var prefTask: SharedPrefTask = SharedPrefTask
prefTask.doSomeWork()
Approach 2
SharedPrefTask.doSomeWork()
Which is the correct approach here?
Both are technically correct and will have the same outcome. When you use your first approach prefTask: SharedPrefTask = SharedPrefTask all you're really doing is making a variable that references the object. So if you were to call prefTask.doSomeWork() it would be the exact same as calling SharedPrefTask.doSomeWork().
Knowing this, it seems like it would be best to just go with your second approach since it is more clear and uses less code.
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
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
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
In the last year I've become a mobile developer and a functional programming admirer.
In each of the mobile arenas there are components with lifecycle methods that make up the meat of the app. The following will use Android and Kotlin as examples, but the same applies to iOS and Swift.
In Android, there are Activity's with lifecycle methods like onCreate(). You might also define a function, onButtonClicked(), which will do exactly what the name describes.
For the purposes of the question, let's say there's a variable defined in onCreate() that is used in a button click handler onButtonClickedPrintMessageLength() (This is usually the case - onCreate() is essentially Activity's setup method).
The example class would look like this:
class ExampleActivity: Activity() {
var savedStateMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedStateMessage = "Hello World!"
}
fun onButtonClickedPrintMessageLength() {
System.out.println(savedStateMessage?.length)
}
}
Notice the declaration of savedStateMessage as a String? (nullable string) and the use of ?. (null safe call). These are required because the compiler cant guarantee that onCreate() will be called before onButtonClickedPrintMessageLength(). As developers though, we know that onCreate will always be called first* **.
My question is how can I tell the compiler about the guaranteed order of these methods and eliminate the null checking behavior?
* I suppose it's possible to new up our ExampleActivity and call onButtonClickedPrintMessageLength() directly, thus sidestepping the Android framework and lifecycle methods, but the compiler/JVM would likely run into an error before anything interesting happened.
** The guarantee that onCreate is called first is provided by the Android framework, which is an external source of truth and might break/function differently in the future. Seeing that all Android apps are based on this source of truth though, I believe it's safe to trust.
Although this won't answer your actual question, in Kotlin you can use lateinit to tell the compiler that you'll initialize a var at a later point in time:
lateinit var savedStateMessage: String
You'll get a very specific UninitializedPropertyAccessException if you try to use this variable before initializing it. This feature is useful in use cases like JUnit, where you'd usually initialize variables in #Before-annotated method, and Android Activitys, where you don't have access to the constructor and initialize stuff in onCreate().
As mentioned in another answer, lateinit is available as an option to defer initialization to a later point in a guaranteed lifecycle. An alternative is to use a delegate:
var savedStateMessage: String by Delegates.notNull()
Which is equivalent, in that it will report an error if you access the variable before initializing it.
In Swift this is where you would use an implicitly-unwrapped Optional:
class Example: CustomStringConvertible {
var savedStateMessage: String! // implicitly-unwrapped Optional<String>
var description: String { return savedStateMessage }
init() {
savedStateMessage = "Hello World!"
}
}
print(Example()) // => "Hello World!\n"
By using the operator ! at the end of String in the second line of the example you are promising that the variable will be set before it can be used. This is accomplished in the init method of the example. It's still an Optional but code can treat it as a String since it will be automatically unwrapped before each use. You must take care that the variable is never set to nil when it might be accessed or a runtime exception may be generated.