I have noticed that Kotlin synthetic properties don't work on CustomViews. I don't know if it is intended or not. When reading the generated java class, i see the cache is present:
private HashMap _$_findViewCache;
but is never used. Instead, any time a view is needed, findViewById is called. Is this the default behavior? Synthetic properties only working on activities and fragments?
This works now. Blog post on kotlin-android-extensions
The custom class shall have the cache generated and use it:
itemTitle.text = "Hello World!"
this in a custom view class, becomes:
((TextView)this._$_findCachedViewById(id.itemTitle)).setText((CharSequence)"Hello World!");
utilizing the cache properly
Related
I'm new to android studio and I'm leaning it from this video
At 50:45 he says that we can directly use the id without findViewById (), for him it shows just import that Id, but when I tried the same I'm not getting what he is getting. Can anyone tell me what's wrong, is that feature removed in the latest update??
"kotlinx.android.synthetic is no longer a recommended practice. Removing in favour of explicit findViewById"
So, this feature`s been deprecated almost a year ago.
The new recommended way of working with view tree is View Binding.
Or you could write some lazy extension function that uses findViewById under the hood.
You can use the Kotlin Android Extensions check here or with the help of data binding or view binding you can just use the id directly in to your java activity class
The way you're talking about is Kotline Extensions for view, for which you apply it in the build.gradle file using apply plugin: 'kotlin-android-extensions', sync the project as prompted by the Android studio and it starts working.
But, Kotlin extensions has also been deprecated for view binding which is null-safe, also easy to implement and better.
To read about view binding, read the Android documentation on ViewBinding here and about migrating here. You can also go with this article to help with setting up Android view binding.
In kotlin to access an element in the layout you do not need to do:
val k = findViewById(R......)
The element should be automatically imported into the kotlin file that connected to the view F.E if you have a text element in your main activity, in kotlin you access it by using it's id directly in the file that inflates that view and the import should be added automatically like this.
import kotlinx.android.synthetic.main.activity_main.view.*
However in few recent projects I noticed that this does not happen automatically.
You are correct, the Kotlin synthetics have quite a lot of similarities to the View Binding feature. The main advantage view binding has is that it's a bit harder to use the wrong binding class (with synthetics, you could quite easily import the wrong synthetics class if you have views in multiple layouts with the same ID).
I believe it's deprecated for a number of reasons, namely the type safety issue and the fact that it doesn't work with Java.
I've wrote a short tutorial on view binding here.
After some digging I found that Kotlin Android Extensions is now deprecated. Here is the guide to use the new method.
https://developer.android.com/topic/libraries/view-binding
Another option is to add the plugin in the app.gradle file.
plugins {
...
id 'kotlin-android-extensions'
}
After doing this two questions comes to mind:
Why did they remove the imports?
isn't the method that they demonstrated just doing the exact same thing as in it's importing the whole view?
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
Android Studio shows the error
Unexpected implicit cast to CharSequence: layout tag was TextView
at this code
findViewById<TextView>(R.id.tv_name).text = "text"
If I write
(findViewById<TextView>(R.id.tv_name) as TextView).text = "text"
Everything is fine.
The question is why this happens? Doesn't findViewById<TextView> already have type TextView?
You can use Kotlin Android Extensions
Kotlin Android Extensions are Kotlin plugin that will allow to recover views from Activities, Fragments and Views in an amazing seamless way.
you can directly use
tv_name.text = "text"
no need of findViewById
Reference
https://antonioleiva.com/kotlin-android-extensions/
You can directly use all the views using DataBinding. Less code and very advance feature of android. There are many articles for Android DataBinding.
https://developer.android.com/topic/libraries/data-binding/index.html
This is only warning of lint. You can ignore it with #SuppressLint("WrongViewCast"). This happend because of usage of generic types from Java in Kotlin.
First of, Kotlin under the hood, just wraps up java findViewById method. Up to API 26 explicit cast was neccessary as method returned View, but now it returns . Check this answer No need to cast the result of findViewById?
If you dive into the source code, through invokations of findViewById, you'll get to Window.findViewById method, and if you look to description of it in documentation, you'll see one note there, which says that: "In most cases -- depending on compiler support -- the resulting view is automatically cast to the target class type. If the target class type is unconstrained, an explicit cast may be necessary." https://developer.android.com/reference/android/view/Window.html#findViewById(int)
I don't know what "unconstrained" actually means in this context, but as i understand, in some cases cast is required in others is not, so just deal with it. For example, i tried to add some param to ImageView and compiler didn't show any kind of warnings:
findViewById<ImageView>(R.id.iv).adjustViewBounds = true
I used synthetic property in my code.But wondering for how and when it actually initialise each view in android.
We simply provide import and access each view by its id. When it allocate memory for view object?
This is easy enough to investigate by decompiling a Kotlin file where you use Kotlin Android Extensions. (You can do this by going to Tools -> Kotlin -> Show Kotlin Bytecode and then choosing Decompile in the pane that appears.) In short, it's nothing magical, it just uses findViewById and then casts the View to the concrete type for you.
If you use it inside an Activity or a Fragment, these get cached in a Map so that the lookup only occurs once. After that, you're only paying the costs of fetching a map entry by the ID as the key.
You can also use it on a ViewGroup to find a child with a given ID in it, in these cases, there's no caching, these calls are replaced by simple findViewById calls that will happen every time that line is reached. This second syntax looks something like this:
val view = inflater.inflate(...)
view.btnLogin.text = "Login"
And it will translate to something similar to this in the bytecode:
View view = inflater.inflate(...);
Button btnLogin = (Button) view.findViewById(R.id.btnLogin);
btnLogin.setText("Login");
Note that the actual View instances are still created when your layout is inflated. Kotlin Android Extensions is only syntactic sugar over findViewById calls.