“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

ViewBinding Usage Scenario Supplementary

In the last article, WHY do I recommend you replace findViewById with a ViewBinding? ViewBinding and DataBinding are the two important components of the DataBinding and ViewBinding. They are not used in the Adapter and include.

So with this article, this article is going to talk about how to use a Viewbinding in an Adapter, and how to use it if you have an include tag

Use of ViewBinding in Adapter

Write a simple page that contains a list. The list has some data:


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    tools:viewBindingIgnore="false"
    android:background="@color/white"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>
Copy the code
<? The XML version = "1.0" encoding = "utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp"> <TextView android:id="@+id/tv_item_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" Android :text=" @color/black" Android :textSize="20dp" /> <TextView android:id="@+id/tv_item_index"  android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:text="1" android:textColor="@color/black" android:textSize="20dp" /> </RelativeLayout>Copy the code

To demonstrate, create two very simple XML files, one page on a RecyclerView, list adapter simple item. Just two texts. Let’s focus on how to bind views using ViewBinding in the Adapter.


class ViewBindingTestAdapter(val mList: ArrayList<ItemBean>):RecyclerView.Adapter<BindViewHolder>() {
   // Create a ViewHolder for our Adapter to use. Note that the argument we pass is an instance of the Viewbinding generated by the XML we generated
    class BindViewHolder(var itemBinding: ItemBindingLayoutBinding) :
        RecyclerView.ViewHolder(itemBinding.root) {
        fun bind(itemBean: ItemBean) {
            itemBinding.tvItemName.text = itemBean.itemNamed
            itemBinding.tvItemIndex.text = itemBean.itemIndex.toString()
        }
    }
  // Create a View using the Binding generated by the layout and pass it to the ViewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindViewHolder {
        val itemBinding =
            ItemBindingLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return BindViewHolder(itemBinding)
    }


    override fun getItemCount(a): Int {
        return mList.size
    }

    override fun onBindViewHolder(holder: BindViewHolder, position: Int) {
        var itemBean = mList.get(position)
        holder.bind(itemBean)
    }
}
Copy the code

Then let’s see how our main class uses Adapter

class ViewBindingActivity : AppCompatActivity() { lateinit var binding: ActivityViewBindingLayoutBinding lateinit var adapter: ViewBindingTestAdapter lateinit var mList: ArrayList<ItemBean> override fun onCreate(savedInstanceState: Bundle?) {// Use ViewBinding to bind the view super.onCreate(savedInstanceState) binding = ActivityViewBindingLayoutBinding.inflate(layoutInflater) val view = binding.root; Private fun initView() {mList = ArrayList() for (I in 1.. 100) {var itemBean = itemBean () itemBean. ItemNamed = "$I" itemBean. ItemNamed = "$I" itemBean ViewBindingTestAdapter(mList) binding.rvList.setHasFixedSize(true) binding.rvList.layoutManager = LinearLayoutManager(this) binding.rvList.adapter = adapter } }Copy the code

Is it super easy to use? Replace Adapter in your project with ViewBinding. You can most likely avoid the null pointer problem

Use of ViewBinding in include

There are two types of include tags. One is the merge tag, which is much simpler. We need to define an ID for our include so that the ViewBinding will automatically add the include when the binding class is generated. Look at the code

<inlude>Don’t take<merge>The label

Write a layout that does not include the merge tag

Create a layout with three text buttons

Then include in the interface we are using:

<? The XML version = "1.0" encoding = "utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical" tools:context=".MainActivity" tools:ignore="MissingConstraints" tools:viewBindingIgnore="false"> <TextView android:id="@+id/tv_viewBinding" android:layout_width="match_parent" android:layout_height="50dp" android:background="#ac99FF" android:gravity="center" android:text="ViewBinding" Android :textSize=" @color/design_default_color_primary_dark" Android :textSize="20dp" /> <include android:id="@+id/include_login" layout="@layout/include_login_layout" /> </LinearLayout>Copy the code

Then we can happily use it in our code:

class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.tvViewBinding.setOnClickListener { val intent = Intent() intent.setClass(this, ViewBindingActivity: : class. Java) startActivity (intent)} / / Id of the definition of first call us to include specific view in the call binding.includeLogin.tvLoginFacebook.setOnClickListener { Log.e("pLog", "Facebook login")} binding. IncludeLogin. TvLoginGoogle. SetOnClickListener {the e (" pLog." "Google login")} binding. IncludeLogin. TvLoginTwitter. SetOnClickListener {the e (" pLog ", "twitter login")}}}Copy the code

See here, do you have a lot of question marks? Let’s look at the specific Binding class he generates

We have generated a corresponding Binding class, and we refer to the ActivityMainBinding class code:

public final class ActivityMainBinding implements ViewBinding { @NonNull private final LinearLayout rootView; / / we define the include tag id generated layout @ NonNull public final IncludeLoginLayoutBinding includeLogin; @NonNull public final TextView tvViewBinding; private ActivityMainBinding(@NonNull LinearLayout rootView, @NonNull IncludeLoginLayoutBinding includeLogin, @NonNull TextView tvViewBinding) { this.rootView = rootView; this.includeLogin = includeLogin; this.tvViewBinding = tvViewBinding; } @Override @NonNull public LinearLayout getRoot() { return rootView; } @NonNull public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) { return inflate(inflater, null, false); } @NonNull public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, boolean attachToParent) { View root = inflater.inflate(R.layout.activity_main, parent, false); if (attachToParent) { parent.addView(root); } return bind(root); } @NonNull public static ActivityMainBinding bind(@NonNull View rootView) { // The body of this method is generated in a  way you would not otherwise write. // This is done to optimize the compiled bytecode for size and performance. int id; missingId: { id = R.id.include_login; View includeLogin = ViewBindings.findChildViewById(rootView, id); if (includeLogin == null) { break missingId; } // Draw different IncludeLoginLayoutBinding binding_includeLogin = IncludeLoginLayoutBinding. Bind (includeLogin); id = R.id.tv_viewBinding; TextView tvViewBinding = ViewBindings.findChildViewById(rootView, id); if (tvViewBinding == null) { break missingId; } return new ActivityMainBinding((LinearLayout) rootView, binding_includeLogin, tvViewBinding); } String missingId = rootView.getResources().getResourceName(id); throw new NullPointerException("Missing required view with ID: ".concat(missingId)); }}Copy the code

I think you read his logic. So what do we do with the merge label

<inlude> 带 <merge>The label

When we include another layout within a layout, we usually use a layout with a

tag, mainly to reduce View hierarchy problems. Can we just define the ID for include and use it as if it were not included with the merge tag? Give it a try. Define a simple layout with the merge label

<? The XML version = "1.0" encoding = "utf-8"? > <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" Android :text=" @color/black" Android :textSize="20dp" android:textStyle="bold" /> </merge>Copy the code

And then you just include it, and you define an ID. It is also ok to preview the actual drawings. Is that all right? So let’s run this.

Ideal is full, reality is very skinny, after running, directly to my big mouth

        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
     Caused by: java.lang.NullPointerException: Missing required view with ID: com.example.binding_module:id/include_merge
        at com.example.binding_module.databinding.ActivityMainBinding.bind(ActivityMainBinding.java:91)
        at com.example.binding_module.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:58)
        at com.example.binding_module.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:48)
        at com.example.binding_module.MainActivity.onCreate(MainActivity.kt:15)
        at android.app.Activity.performCreate(Activity.java:8000)
        at android.app.Activity.performCreate(Activity.java:7984)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:223) 
        at android.app.ActivityThread.main(ActivityThread.java:7656) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
Copy the code

I can’t find include_merge. If you can’t use include to define an ID, can you use other methods? The layout of the merge also generates the corresponding binding class. Hey hey. I wonder if we could just use it. Have a try…



The Binding class is generated and we use it directly.

class MainActivity : AppCompatActivity() { lateinit var binding: ActivityMainBinding / / define the merge tag generates Binding class lateinit var includeMergeLayoutBinding: IncludeMergeLayoutBinding override fun onCreate(savedInstanceState: Bundle?) {super. OnCreate (savedInstanceState) binding = ActivityMainBinding. Inflate (layoutInflater) / / through the bind method initialized includeMergeLayoutBinding = IncludeMergeLayoutBinding.bind(binding.root) setContentView(binding.root) binding.tvViewBinding.setOnClickListener { val intent = Intent() intent.setClass(this, ViewBindingActivity::class.java) startActivity(intent) } binding.includeLogin.tvLoginFacebook.setOnClickListener { The e (" pLog facebook ", "login")} binding. IncludeLogin. TvLoginGoogle. SetOnClickListener {the e (" pLog." "Google login")} binding. IncludeLogin. TvLoginTwitter. SetOnClickListener {the e (" pLog." "Twitter login")} / / direct comparisons with > _ > includeMergeLayoutBinding. TvIncludeMerge. Text = "this way can succeed" IncludeMergeLayoutBinding. TvIncludeMerge. SetOnClickListener {Log. E (" pLog ", "click the include merge label layout")}}}Copy the code

Successful output of our print. Perfect.

conclusion

ViewBinding greatly reduces our workload and avoids null Pointers and cast errors. Also, you can support include tags, so you don’t have to define various views in your class and then findViewByid. Just define the ID and use it. Cool, dropping. Use it on the project.

Hello, I am a big cheat, if you like my article, remember to help me a thumbs up