Before Kotlin, Android developers supposed to save reference to the Activity's Views in a variable like this:
Button fooBtn = (Button) findViewById(R.id.btn_foo)
to reduce the amount of the boiler-plate code and the number of findViewById calls.
With the introduction of the Kotlin's Android Extensions we can reference the same Button by simply using:
btn_foo
Questions:
Does the btn_foo have a reference to the Button saved, or does it call findViewById every time?
Do developers still suppose to use variables to store btn_foo to improve app's performance, or just use it directly in the code?
Edit: there is an explanation how Extensions work, however it is still a bit unclear.
It's cached, so findViewById isn't called every time you need it. Storing the variable won't definitely improve the app's performance
One of the Kotlin Android Extension (KAE) developers Ihor Kucherenko confirmed that:
KAE will keep a reference to the view after the first call, instead of using findViewById all the time. That works only for Activities and Fragments.
KAE will not cache data and will use findViewById every time for any other element (except for an Activity/Fragment).
So in case you are going to init a ViewHolder:
class FooViewHolder(view: View): RecyclerView.ViewHolder(view) {
fun bind(day: FooItem.Day) {
btn_foo.text = day.title
}
}
Decompile into Java call will look like:
((Button)this.itemView.findViewById(R.id.btn_foo)).setText((CharSequence)day.getTitle());
which is exactly what you want to avoid.
The developers might be aware of this.
Conclusion: fill free to use KAE without any additional variables, but only for your Activitiies/Fragments.
Related
Imagine the following object
data class CourseState(
val key:Int=0,
val name:String="",
val courses:Courses=Courses())
Implementing the following pattern
private val _courseState = mutableStateOf(CourseState())
val courseState: State<CourseState> = _courseState
I can trigger recomposition of my UI by calling:
_courseState.value = CourseState()
but not by calling:
_courseState.value.courses.addCourse(Course("some course))
this is a bit frustrating because even though the object has clearly changed I am forced to create a whole new instance of the parent object in order to elicit a small change in it.
Now, I know than behind the scenes Compose is using the .equals() method in order to acertain if it should recompose the layout so I ve had a few ideas on how to achieve the desired behaviour.
overwrite the equals method: it would imply a bit of boilerplate code and it would have to be done for the entire set of nested classes that make up my object. this might work but seems dangerous and cumbersome.
use a clone method or a constructor that accepts an instance of its own class as a parameter to create an identical copy of my object that would nevertheless represent a new instance that I can modify and then pass as the mutable state value. sounds easier than the previous optoin but elegance is something different
dive deep into the State and MutableState classes and find out if there is a way to make them behave as I want. I am relying on some of you to have done this before so I dont have to XD
Let me know what you think or if there is some other ovbious solution that has just eluded me so far
There are two options I would consider:
As you mention, create new instances of your objects for every change. With data classes and copy, it's quite easy, it will add some overhead though.
Make all the data that you need to change observable. If you only want to observe them from compose, make it State, otherwise you can use Flow or LiveData. I suppose that your Courses class contains some List to which
you are adding items. Make it a
mutableStateListOf(),
whenever you add something there, composables that use it should
recompose automatically.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
My team has an argument today about var property and object copy. We have an adapter for a RecyclerView. The adapter takes a list of ItemModel, which has a few properties. When any item is clicked, we need to change a property's value of the clicked item.
Some people say we should make the property a var. So, we can assign the new value to it.
Some others say we should make the property val, and use ItemModel.copy and pass the new value to the copy. But to do this, we need to call List.map to create a new list as List is not mutable. This means, to change one property value of one item, we need to loop through the whole list, create a new list with all the items and the new copy of the item that is changed.
In my experiences, the former method looks right to me and the later one does too much unnecessary things and makes bad impact upon performance and resources. But, they were arguing about property mutability and etc. and claimed the later one is a more modern way of programming.
Can anyone with good understanding of android and the functional programming explain for me if the later one really is considered a better way?
It being your recyclerview´s list it should be a mutablelist if the recyclerview should mutate the lists item count effectively (create or delete). val and var on the list does not really matter (in witch case you use val) as you don´t need to reassign the list when you create, update or delete the items. Every single of those operations will not reassign the list object. It´s still the same list, just with different items in it. val and var matters when you want to change value x of item number 3 in the list. Then it (the variable x) has to be var for you to be able to change it, but the list does not.
You use val to indicated that the value will never be changed. It´s for maintainability so weird bugs don´t happen. Like you have another object referencing that list we talked about before. If the list was a var it would be possible to create a new list on the variable and now your two objects no longer point to the same list. Instead one of them still points to the old list. You may not expect that and your program will break. Hence wherever feasible you should be using val. Wherever necessary you should be using var and not complicate your life trying to preserve val unless you have a good reason like this value cannot be changed as it´s referenced all over the place. That's when you use object copy. But not as a default best practice for everything.
That´s just my opinion about it.
On a side note marking a class as a data class will generate the copy method for you. So you can copy that object without even requiring to implement copy. Witch is pretty great!
Setting the property as var is very tempting, however it can lead to errors that could not be even that easy to reproduce. When you are passing around the reference to an object and there are a couple of places where its content is used and could be changed, you might lost control of the actual application state. The code might become unpredictable.
Immutability is the core of the functional programming. It's purpose is to eliminate such vulnerabilities and help programmers write pieces of code that every time execute as expected, because it eliminates the risk of side effects occurrences.
However, as you and your team noticed, the functional approach sometimes may require additional work and resources. But is it worth it? Well, I don't know how large that list should have been to significantly influence the performance by mapping it. And even if currently your objects aren't shared anywhere, you can't be sure that in the future somebody won't change that. So having in mind that the functional approach is less error-prone, I'd say it is worth it.
The second method is contrary to the Basic Design of Kotlin.
With Kotlin you don't Need to write as much lines of Code as in Java, for example the get and set functions which are included in a class. Why do you want to make your Code longer and more complicated in a Language that was designed to shorten the lines of Code?
Another Point is, longer codes can get hard to read and maintain.
The last Point is, that a copy of a class Needs more ressources and time to create and Access than a Var, for me there is no reason why this should be considered as good Approach.
Recently after getting back into Android development, as I was reviewing some code, I noticed that code would reference a control directly by its id without the need to use findViewById. So if I had a textview with an id of tvUsername, I could just call:
tvUsername.setText("john");
In the past I was always using findViewById but am now wondering whether the ability to use a control directly without calling findViewById always existed, or did Google start supporting directly referencing it after some version.
Is findViewById still needed
Is findViewById still needed if you are using JAVA than it is needed,
But if you use Data Binding Library then no need to do findViewById
Also in KOTLIN the findViewById is not needed
You can directly use it like this
tvUsername.text ="john"
for more information read
Kotlin Android Extensions
Goodbye findViewById, say hello to Synthetic Binding
I've been wanting to make the code cleaner, but I do not give it away. I mean...
To name the ids of the views in the XML I use Hungarian notation like this:
<WHAT> <WHERE> <DESCRIPTION> <SIZE>
For example: tvExampleSectionEmptyBig,tvExampleSectionEmptySmall
Previously, using Butter Knife, I did not get too much coding because to do the bindings, I did things like this:
#BindView (R.id.tvExampleSectionEmptyBig) TextView tvEmptyBig;
#BindView (R.id.tvExampleSectionEmptySmall) TextView tvEmptySmall;
The code was much clearer and more reusable since the Hungarian notation used to avoid the confrontation between ids with the same name in different activities, fragments, etc. it was not present in practice more than in XML.
What's going on?
Kotlin has synthetic, which makes your life easier since with putting the id of the view, the binding is done directly, but with such long ids the code is very dirty ... Besides, makes sense that all the views I use in an activity called ExampleSectionActivity, contain within its variable nameExampleSection?
What would I like?
Surely there are better solutions that, but initially, what I feel is to implement a way to rename variables by removing a given String. As I follow a convention in all the names of the ids, it would be something internally in this way:
val tvEmptyBig = tvExampleSectionEmptyBig
val tvEmptySmall = tvExampleSectionEmptySmall
But of course, I would like to do it in an automated way.
On the other hand, I already tried naming the ids without the and to be careful with the imports, but for the moment synthetic fails very occasionally in this respect and I had to rebuild constantly. Especially if I open another instance of Android Studio, which I usually do quite often for consulting other projects I have.
Any idea? :-)
In my opinion, the easies and the most clean thing you can do is this:
private val myTextView: TextView
get() = f_layoyt_text_view
This way you don't have to use ridiculous, at least in 2018, ButterKnife and even more inconvenient findViewById.
For a few weeks, I already take for granted, that with the latest stable updates of Android Studio, there is no problem with repeating names of ids in different activities or fragments. Therefore, it is no longer necessary to put long variable names. Only there is to pay a little bit of attention to the imports, everything works like a charm, more readable and reusable. :-)
In the source code of Activity.java, I see some methods bellow :
public View findViewById(int id) {
return getWindow().findViewById(id);
}
and the definition of getWindow method:
public Window getWindow() {
return mWindow;
}
But as the following rules:
Avoid Internal Getters/Setters
In native languages like C++ it's
common practice to use getters (e.g. i
= getCount()) instead of accessing the field directly (i = mCount). This is
an excellent habit for C++, because
the compiler can usually inline the
access, and if you need to restrict or
debug field access you can add the
code at any time.
On Android, this is a bad idea.
Virtual method calls are expensive,
much more so than instance field
lookups. It's reasonable to follow
common object-oriented programming
practices and have getters and setters
in the public interface, but within a
class you should always access fields
directly.
Without a JIT, direct field access is
about 3x faster than invoking a
trivial getter. With the JIT (where
direct field access is as cheap as
accessing a local), direct field
access is about 7x faster than
invoking a trivial getter. This is
true in Froyo, but will improve in the
future when the JIT inlines getter
methods.
so I want to know why android developers not access this mWindow object directly? If the JIT of the current android versions cannot inline the access, getWindow().findViewById(id) will costs more time than mWindow.findViewById(id), and findViewById is a rather frequently used method.
First: you can't access it because it's private.
Why is it private?
As you said, accessing members directly is faster. On the other hand, you are invoking a method that isn't very fast as it will lookup for some view in the view hierarchy. So using a method instead of a direct access will incur in a small overhead in terms of percentage of the total time that it would take to perform that task.
Anyway, I believe that the reason for this is encapsulation.
You are invoking something you don't own (that is the Android SDK). So, you shouldn't make any assumptions of whats happening "in the other side". Simply use this method and expect that it will return the view you want (or null if it doesn't exists).
Maybe the next version of android will use a different method to lookup a view, not calling getWindow(). If you use this method, they (Google/Android) can simply mark the method as deprecated and "forward" your invocation to the newest implementation. If you were calling directly getWindow(), maybe you would be looking for something that is no longer placed in there.
You can't access the mWindow property directly - it's private.
And I wouldn't care about the speed of findViewById, since you only need to call it once for every view in your layout in your onCreate() method and store the views in members of your activity. You do call findViewById only once per view, don't you? ;-)
However, if you really care about these things, you could call getWindow() for yourself, store it into a local variable and call findViewById on it directly. I wouldn't recommend this because all your performance increasements here are not worth the time and anyway will be obsolete with future versions of the JIT.
If you do this I would be very interested in the amount of microseconds you saved. :-)
We have a reason to smile now...
The android documentation which says to avoid internal getters and setters will change soon, supposedly progruard was added to Gingerbread platform which does a fine job of inlining accessor's, please refer to "Avoid Internal Getters/Setters" is bad advice and these two SO posts.
https://stackoverflow.com/a/6716573/892055
https://stackoverflow.com/a/4930538/892055