Why do
I didn’t take it seriously at that time. I had a problem writing a Demo two days ago and created a new project. The kotlin-Android-extensions extensions in the new project are not integrated with the kotlin-Android-extensions extensions.
One of the reasons why I started using Koltin was that I didn’t have to write findViewById anymore, but now I’m just throwing it away! What a pit.
Coincidentally, just two days after discovering this problem, “Guo Lin” posted an article:
Is the Kotlin-Android-Extensions plugin deprecated? Lifted me up
There is a detailed description of how to use ViewBinding, so I want to use it in my “Play Android”, but there are some minor problems during the use, just listen to me to 🐶
Then put down the Github address of the project: github.com/zhujiang521…
Note: this article does not write the basic usage of ViewBinding, guo Shen wrote the basic usage is much better than mine, you can follow the link above.
Began to make
To do this thoroughly, remove the Kotlin-Android-extensions dependency directly from the main module:
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-android-extensions'
}
Copy the code
Delete the bottom line of the code above and add the ViewBinding dependency:
Android {... buildFeatures { viewBindingtrue}}Copy the code
That’s all pretty simple, but what’s the problem? In fact, this problem can be regarded as a pit dug by myself before. In order to adapt the layout of horizontal and vertical screens, I customized two different controls in the front page of the project. In the layout, the horizontal and vertical screens respectively put their respective layouts.
<com.zj.play.main.HomeBottomLandTabWidget xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/homeLandView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Copy the code
<com.zj.play.main.HomeBottomTabWidget xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/homeView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Copy the code
Very simple, in use directly judge the current screen state to select the loading layout.
override fun initView(a) {
isPort = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
when (isPort) {
true -> homeView.init(supportFragmentManager, viewModel)
false -> homeLandView.init(supportFragmentManager, viewModel)
}
}
Copy the code
It works fine when ViewBinding is not used, but! When a ViewBinding is used, an error is reported:
Configurations for activity_main.xml must agree on the root element's ID.
@+id/homeLandView:
- layout-land
@+id/homeView:
- layout
Copy the code
The error message is obvious because the id of the root element of both layouts must be the same! In this case, put a layer of layout outside the layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.zj.play.main.HomeBottomTabWidget
android:id="@+id/homeView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Copy the code
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.zj.play.main.HomeBottomLandTabWidget
android:id="@+id/homeLandView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Copy the code
After the change, it runs successfully.
The second problem is the use of ViewBinding in custom controls. Guo God wrote in the article about the use of ViewBinding in activities, fragments and Adapter, but did not write how to use it in custom View, actually write it or not, because it is very simple.
private fun initView(a) {
// Load the layout
val binding = LayoutToTopBinding.inflate(LayoutInflater.from(context), this.true)}Copy the code
The first parameter is an inflater, which is a context that can be created directly. The second parameter is a ViewGroup, which is also easy to get in a custom View. The third parameter is whether to bind to the root element. If you want to write it as false, you can also add a View to the layout using addView.
If you need to use it globally, you can define it as a global variable directly, and empty it when not in use.
The third question is what Guo Shen said in the article about the way ViewBinding is written in the Adapter. There is a different opinion in the comment:
Wanted to think and do, use ViewBinding is originally in order not to write the findViewById, the result like the one above to write some words instead of trouble, it is better to direct the findViewById fast, also don’t have to introduce ViewBinding.
Let’s create an Adapter base class:
abstract class BaseRecyclerAdapter<V : ViewBinding> :
RecyclerView.Adapter<BaseRecyclerAdapter.BaseRecyclerHolder<V>>() {
abstract override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerHolder<V>
override fun onBindViewHolder(holder: BaseRecyclerHolder<V>, position: Int) {
onBaseBindViewHolder(position, holder.binding)
}
abstract fun onBaseBindViewHolder(position: Int, binding: V)
open class BaseRecyclerHolder<V : ViewBinding>(val binding: V) :
RecyclerView.ViewHolder(binding.root)
}
Copy the code
The base class code is very simple and without going into too much detail, let’s look at the modified code:
class FruitAdapter(val fruitList: List<Fruit>) : BaseRecyclerAdapter<FruitItemBinding>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerHolder<FruitItemBinding> {
val binding = FruitItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BaseRecyclerHolder(binding)
}
override fun onBaseBindViewHolder(holder: BaseRecyclerHolder<FruitItemBinding>, position: Int) {
val fruit = fruitList[position]
binding.apply{
fruitImage.setImageResource(fruit.imageId)
fruitName.text = fruit.name
}
}
override fun getItemCount(a) = fruitList.size
}
Copy the code
I didn’t write much less code, but I felt a little cleaner.
To the end
The rest was enough as written by Guo God, and the modification was quite simple. After a few hours of “Playing Android”, I changed the whole project into ViewBinding.
Let’s hope Google doesn’t jump into ViewBinding too soon, because Compose is still waiting on ViewBinding…
Before the end, wish everyone a happy New Year, after all, not out of the first month is the year! But now a little late, old age, I wish you all: happy old age!