Recently I migrated my project to ViewBinding and as a way to make it less verbose, I decided to expose it through get() property and it seems to be working fine, but some other developers are saying that it may cause memory issues because it's assigning a value to a variable, which I think it's not doing this, since it's exposing through the get() property. Example:
class MyActivity : AppCompatActivity() {
private val textView: TextView get() = binding.textViewID
private val binding by lazy { MyActivityBinding.inflate(layoutInflater) }
}
can someone confirm this?
When you define a property with a getter and no initial assignment, there is no backing field generated. So no, this is not wasting memory.
The way you wrote it on one line looks very similar to code where there is no getter defined and you are assigning an initial value to a backing field. Maybe your colleagues misread your code. I usually define getters on the next line so it looks distinct. Otherwise, it is easy to accidentally omit get() when you intended to include it.
Even if it were creating a backing property, surely you don't have enough views referenced that it would even approach an amount of memory use that you should waste your time worrying about it.
Related
I read document, but I don't still get it.
The differences between this
private val myClass: MyClass = mockk(relaxed = true)
and this.
private val myClass: MyClass = mockk()
What I understood is if relaxed is true. Then, all the member fields or methods will return default values. Otherwise, not. is that correct understanding?
If so, setting always relaxed = true is better. But In this video, Ryan uses both. why?
https://youtu.be/60KFJTb_HwU?t=1015
If you're trying to call a mock method that doesn't know what to return and relaxed is not set to true you'll get an exception thrown. This is made, so tests are less likely to introduce unpredictable behavior, due to the default values returned by methods that the developer does not purposely mock.
In the linked video the view methods are probably never called, therefore no "relaxed" is necessary. You can also use "relaxedUnitFun", which works only for methods returning Unit, handy for example for classes responsible for events logging.
This is a double-edged weapon though, as "relaxing" everything deprives you of the security mechanism mentioned above. If this is what you want, you can also configure this globally, check https://mockk.io/#settings-file
To quote their documentation:
A relaxed mock is the mock that returns some simple value for all functions. This allows you to skip specifying behavior for each case, while still stubbing things you need. For reference types, chained mocks are returned.
source
The following code shows up "Property must be initialized or be abstract" error.I understand that I can use lateinit in such cases but I wanted to know the reason behind the restriction .
class Student{
val s:String
}
In the case of a non-nullable property like in your example, the reason is necessity. Java implicitly gives member variables a value of null. In Kotlin, a non-nullable property cannot have a value of null, so you have to give it an instance of something to be the starting value.
But even if you declared it as nullable String?, Kotlin will require you to specify the starting value. Kotlin avoids making implicit assumptions about the intent of your code. Kotlin's design goals are to make code more readable and robust. The designers have done research on common causes of bugs in other languages, and have made Kotlin more restrictive in areas that have been frequent sources.
I found the answer for Kotlin Lazy objects, using isInitialized() here: Kotlin: Check if lazy val has been initialised
But seems like dagger.Lazy doesn't have the same public method.
This is how I lazily inject using Dagger:
#Inject internal lateinit var someService: dagger.Lazy<SomeService>
How to check if someService is already initialized without calling someService.get() which will initialize it? Other than introducing a boolean flag and keep track of it ourselves..
Thanks!
There isn't a way to check; Lazy only has one method, get, making it a functional interface or "Single Abstract Method (SAM)" interface much like JSR330's Provider, Guava's Supplier, and JDK8 Supplier.
This abstraction is important, because in Dagger the definition of Lazy is more complicated and there is more than one implementation. For scoped bindings, the internal InstanceFactory itself implements Lazy, so the built in Provider<Lazy<T>> available for each T in the graph can be implemented using a class ProviderOfLazy that can simply return the internal Provider or InstanceFactory rather than creating a new wrapper instance. With that in mind, the instance of Lazy you interact with might be a shared one, so a hypothetical isInitialized might be ambiguous: Does it mark that the scoped binding was ever accessed, or just the local Lazy injection point you requested? Would that behavior change based on whether you mark the binding scoped or not in a faraway Module file? You could also imagine an implementation where every Lazy injection got its own instance, and each would locally track whether it had ever had its get called regardless of scoping. This is in contrast to Kotlin's Lazy, in which each instance wraps exactly one initializer function and consequently has less ambiguity.
Also, Kotlin's Lazy has multiple synchronization modes from which you can select, some of which have undefined behavior when called concurrently. isInitialized is never synchronized in any of those modes, so in a concurrent environment you might receive false while the value is in mid-construction, or it may even be fully constructed on a different thread and the value is simply not yet visible from the thread calling isInitialized.
If you need to be able to check on a Lazy-like status, you'll need to specify how wide you care about construction and how thread-safe you want the result to be, which is custom enough to warrant your own implementation.
Was just wondering, why is it better to use backing property for MutableLiveData, instead of just exposing getter function that returns the MutableLiveData property as live data. For example:
Why this code
private val _registeredDevicesObservable: MediatorLiveData<List<Data>> = MediatorLiveData()
val registeredDevicesObservable: LiveData<List<Data>> = _registeredDevicesObservable
is better or more acceptable than this one
private val _registeredDevicesObservable: MediatorLiveData<List<Data>> = MediatorLiveData()
fun registeredDevicesObservable(): LiveData<List<Data>> = _registeredDevicesObservable
As also when this getter function is keeping the LiveData immutability and keeps me from having that little annoying underscore syntax when accessing the property inside the view model.
It's just less idiomatic in the language to use a function that simply returns an already-available object. You're free to do it any way you like, but if others have to work with your code, it will be easier to understand and work with if you follow general conventions.
There isn't as strong a convention about whether the backing property should have a leading underscore in the name, so if you don't like it, don't use it.
One reason to stick with these conventions is there is a proposed upcoming language feature to allow you to do this without a backing property, and so if you're following the conventions, it will be very easy to update your code to eliminate the backing property.
I'm able to access my layout views(like button, TextView, EditText etc) directly inside the activity by their ids defined in layout xml file in Kotlin android project.
So, do we need to use findviewbyId(), or butterknife lib in kotlin android project?
StudentActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val studentViewModel = getStudentViewModel()
updateButton.setOnClickListener {
val name = nameEditText.text.toString()
val age = ageEditText.text.toString()
val subject = subjectEditText.text.toString()
studentViewModel.updateStudentRecord(
Student(
name,
Integer.parseInt(age),
subject
)
)
}
}
}```
ButterKnife is an old solution for view binding. It has less boilerplate code than old findviewbyId way but because of annotation processors it impacts build time speed and doesn't provide Null safety and Type safety. A better solution is kotlinx.android.synthetic that you used in your example but it has some problems too. For example, if you set your content view to a layout, then type an id that only exists in a different layout, the IDE lets you autocomplete and add the new import statement. Unless the developer specifically checks to make sure their import statements only import the correct views, there is no safe way to verify that this won’t cause a runtime issue. As everything is global, one has to be careful to make sure that they only use views they are expecting and ignore the autocomplete. DataBinding and ViewBinding are the best solutions for now. They are similar at first look. Both generate binding classes that you can use to reference views directly with support Null safety and Type safety, but there are differences:
DataBinding approach needs you to add <layout> tag to your XML layout in order to enable the data binding process
ViewBinding doesn’t support layout variables or layout expressions, so it can’t be used to bind layouts with data in XML
ViewBinding is faster than DataBinding in build time because it does n't use annotation processors.
I think you will not use anymore, just if you want? But I believe that is not because of the Synthetic Accessors, it's because of the Data Bindings and the announced this year, View Binding
Nope, here is the the magic of kotlin. Just use your id from the layout file (xml) and directly use it. Like:
button.setOnClickListener {}
and so on. hope it will help.