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.
Related
I'm trying to create a fake class for my repository to test a view model.
As far as I understood, the key element here is to create two classes with a common interface so both classes would contain the same methods.
The problem is I get a Type mismatch when trying to initialize an object.
I tried to do the same in a simplified manner:
class fakeClass1 : fakeInterface {
override fun getAllData(): String {
return ""
}}}
class fakeClass2 : fakeInterface {
override fun getAllData(): String {
return ""
}}
interface fakeInterface {
fun getAllData(): String}
val fakeClass: fakeClass1 = fakeClass2()
But that didn't work either.
What am I missing?
Ok, I figured it out.
I was wrong to think that those two classes should be interchangeable.
I solved it by making the ViewModel take the common interface in its constructor instead of the actual repository class. This allows the ViewModel to take any class which implement this interface as it's repository.
I think you worked it out, but just so you're clear (this is an important, fundamental thing!)
val fakeClass: fakeClass1 = fakeClass2()
This is defining a variable called fakeClass that refers to an object with the fakeClass1 type. Then you assign an object with the fakeClass2 type.
But a fakeClass2 is not a fakeClass1, neither is a superclass of the other, so you can't treat one as the other. Your example is simple, but imagine you added coolFunction() to fakeClass1 - they'd now happen to have different structures, and trying to call that method on an object that doesn't have it would cause a crash.
The only thing those classes have in common, is that they both have the fakeInterface type - they are fakeInterfaces, and that guarantees they implement the stuff in that interface (your getAllData function in this case). So if you treat them both as that type instead:
val fakeClass: fakeInterface = fakeClass2()
you can use either one, because they're both fakeInterfaces (similar to how Ints and Doubles are different but they're both Numbers). Because fakeClass is now a fakeInterface, you can only access the functions and properties that a fakeInterface has - you can't call coolFunction() even if you happened to pass in a fakeClass1, because fakeInterface doesn't have that.
(You could cast the variable to fakeClass1, basically saying "oh by the way this object is actually this type as well", but at that point the type system can't guarantee you're correct unless you're explicitly checking fakeClass is fakeClass1, and it'll warn you if that's the case)
The Java tutorials are pretty good and they'll give you an overview about how the types each form a kind of "contract" you work with
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 have a class that extends another, but in this class I do not want to call the super constructor.
How can I solve it?
Here is a snipet of my code
class SubarticlePagerAdapter(fragmentManager: FragmentManager, context: Context, var selectedArticleName: String) : ArticlePagerAdapter(fragmentManager, context) {
var subarticleDao: ArticleDao
var itemCount = 0
init {
ApplicationHelper().getApplication(context).appComponent.inject(this)
subarticleDao = ApplicationHelper().getApplication(context).subarticleDaoSession.articleDao
initBundles(context)
}
override fun initBundles(context: Context?) {
}
}
My problem, when this constructor is called, parent class constructor run first, and initBundles() will be called from there, but at that time subarticleDao and selectedArticleName are not set and I get exception.
TL;DR
I'd advise you to move the code from the init block to the initBundles function and use your variables there after initialization. Then there would be no need to avoid calling the superclasses constructor.
Extensive Answer
I think you should think about what you want to do with your design. Working around the idioms of a language is not very often a good idea or a sign of good design - at least when kotlin is your language :)
What you did with your code (overriding a - possibly abstract - method, initBundles from your superclass is pretty much the template method pattern. So it seems to me the purpose of initBundles is to let subclasses customize parts of the initialization... What basically is what you do in your init block.
EDIT: As Paul pointed out in the comments, you can't use the member selectedArticleName before your base classes initialization has finished. So if the base class calls initBundles during its initialization, then properties in the subclass won't be initialized as also stated at Paul's link.
Since in the snippet you don't use selectedArticleName, you could just move your initialization stuff to the initBundles function and init your subarticleDao there.
However, if you need to use your subclasses properties at that point, I'd really advise you to rethink your design. There should be several ways to solve this, but to decide what would suits your requirements best one would need further insight into the intentions you have with your design.
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
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