1. 程式人生 > >Kotlin Android Extensions: Using View Binding the right way

Kotlin Android Extensions: Using View Binding the right way

Kotlin Android Extensions: Using View Binding the right way

How to use View Binding in classes other than Activities, Fragments and Views

https://proandroiddev.com/kotlin-android-extensions-using-view-binding-the-right-way-707cd0c9e648

If you use Kotlin Android Extensions, you’ve probably heard of View Binding feature. “

Say goodbye to findViewById” by Antonia Leiva is a very popular article.

The obvious benefit of using View Binding by KTX is it makes your code more concise. You don’t have to use findViewById or the @BindView annotation of ButterKnife library. One less line of code for each view used. Sounds great! But that’s only the 

Hummock!

Hummock is the top part of the iceberg and Bummock is the bottom part.

I’ll introduce you the Bummock: _$_findCachedViewById

When you use KTX and import your view declared in the xml to your class, the compiler generates a special method for you, that is _$_findCachedViewById. To see that you need to open the Kotlin bytecode and decompile it to Java as described 

here. I want to dig deeper to point out a common pitfall that is not so obvious.

In the official documentation, it says:

“Android Extensions plugin supports different kinds of containers. The most basic ones are  ActivityFragment and  View, but you can turn (virtually) any class to an Android Extensions container by implementing the  LayoutContainerinterface…”

When you use View Binding extensions in a class other than “Activity, Fragment or View” you must implement LayoutContainer interface. That’s not so true. If you pass a view instance to your class, you can simply call your KTX view on the passed instance. If you are in a ViewHolder class, you can directly use itemView:

 

DONT EVER DO IT!

This prevents the compiler from caching your views. Here is the proof:

 

Decompiling the generated Kotlin bytecode to Java, you can see findViewById is invoked.

So you search the web trying to find the solution and see that you need to implement the LayoutContainer interface. There comes the trap. Now your ViewHolder looks like this:

 

As soon as you implement the LayoutContainer interface, findViewCache variable and corresponding findCachedViewById & clearFindViewByIdCache methods are generated. But if you take a closer look, neither of those are used in bind method or anywhere else. So the cache mechanism is still not working.

 

The right way:

 

You need to remove the itemView before textViewHummock. When you do so, the import statement also changes

from:

 

to:

 

Take a look at the decompiled code:

 

Now it uses _$_findCachedViewById in bind method. You did a great job!

TL;DR

In your ViewHolder, don’t ever write the following:

itemView.textViewBlaBla.text = myItem.blaBla

It kills the performance of your view holder. Use LayoutInflater interface!