Android解放双手的利器之ViewBinding

文章目录

    • [1. 背景](#1. 背景)
    • [2. ViewBinding是什么](#2. ViewBinding是什么)
    • [3. 开启ViewBinding功能](#3. 开启ViewBinding功能)
    • [4. 生成绑定类](#4. 生成绑定类)
    • [5. 使用ViewBinding](#5. 使用ViewBinding)
      • [5.1Activity 中使用](#5.1Activity 中使用)
      • [5.2 Fragment 中使用](#5.2 Fragment 中使用)
      • [5.3 ViewHolder 中使用](#5.3 ViewHolder 中使用)
    • [6. ViewBinding的优点](#6. ViewBinding的优点)
    • [7. 与 dataBinding 对比](#7. 与 dataBinding 对比)

1. 背景

写代码最繁琐的是什么?重复的机械操作。我们刚接触Android开发时最常写的操作肯定少不了findViewById 的身影。如果页面简单,负担还好,多写几行而已,但如果界面中存在几十上个View呢?再或者,重复的做一件枯燥的事几百次呢?这时候就会敲代码敲到手抽筋,有点生无可恋了吧。

2. ViewBinding是什么

这时候你的救星它来了!解放你的双手,效率提升十倍!它就是 ViewBinding !

ViewBinding ,顾名思义是"视图绑定"。它可以自动为 XML 布局文件生成一个绑定类,通过这个绑定类,你可以直接拿到布局中的View,再也不用 findViewById 的一个个去找了。

ViewBinding 是AndroidStudio3.6以后就支持的功能,现在大家的Android Studio版本应该都是202x.x.x这种新的年月日版本了吧。Android Studio4.2.2之后就采用这种新版本命名法了。

3. 开启ViewBinding功能

在 module级别的 build.gradle 文件中,添加如下代码:

groovy 复制代码
android {
    ...
    buildFeatures {
        viewBinding true
    }
}

如果你的 build.gradle 是 build.gradle.kts 这种文件,则这样添加代码:

groovy 复制代码
android {
    ...
    buildFeatures {
        viewBinding = true
    }
}

4. 生成绑定类

添加配置代码之后,会提示你点击 sync 同步代码,然后 build 一下工程 AS 会自动为你的工程生成绑定类代码,目录在app/build/generated/data_binding_xxx下。

生成的绑定类命名规则是,将 XML 文件的名称转换为"驼峰命名法"的形式,并在末尾添加"Binding"一词。比如,你的布局文件名是:activity_main.xml,那么生成的绑定类名是: ActivityMainBinding

默认情况下,AS会对工程中的所有xml文件生成绑定类。如果不想为某个布局文件生成,则可以将 tools:viewBindingIgnore="true" 属性添加到该布局文件的根视图中,例如:👇

xml 复制代码
<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
    ...
</LinearLayout>

5. 使用ViewBinding

ViewBinding可以用在各种需要布局与代码交互的地方,如Activity、Fragment、ViewHolder等

5.1Activity 中使用

首先是布局,不需要做任何修改😄,比如布局:activity_main.xml👇:

xml 复制代码
<?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:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="100dp"
        android:layout_height="100dp" />

    <Button
        android:id="@+id/btn_ok"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮" />
</LinearLayout>
  • 使用 ViewBinding 前

    MainActivity.kt 👇:

    kotlin 复制代码
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.widget.Button
    import android.widget.ImageView
    import android.widget.TextView
    
    class MainActivity : AppCompatActivity() {
    
        private var tvTitle: TextView? = null
        private var ivIcon: ImageView? = null
        private var btnOk: Button? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            tvTitle = findViewById(R.id.tv_title)
            ivIcon = findViewById(R.id.iv_icon)
            btnOk = findViewById(R.id.btn_ok)
            tvTitle?.text = "你好"
            ivIcon?.setBackgroundColor(Color.RED)
            btnOk?.text = "确认"
            btnOk?.setOnClickListener { 
                Toast.makeText(this@MainActivity, "点击了", Toast.LENGTH_SHORT).show()
            }
        }
    }
  • 使用 ViewBinding 后

    MainActivity.kt 👇:

    kotlin 复制代码
    import android.graphics.Color
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.widget.Toast
    import com.example.mtes.databinding.ActivityMainBinding
    
    class MainActivity : AppCompatActivity() {
    
        private var activityMainBinding: ActivityMainBinding? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(activityMainBinding?.root)
            activityMainBinding?.tvTitle?.text = "你好"
            activityMainBinding?.ivIcon?.setBackgroundColor(Color.RED)
            activityMainBinding?.btnOk?.text = "确认"
            activityMainBinding?.btnOk?.setOnClickListener {
                Toast.makeText(this@MainActivity, "点击了", Toast.LENGTH_SHORT).show()
            }
        }
    }

到这里,相信你已经学会了 ViewBinding 的基本用法,体会到它的便捷了吧,再见了 findViewById 😄。

5.2 Fragment 中使用

这里就省略布局的举例了,跟Activity一样,拿到binding后,直接点出来你想访问的view即可。相信聪明的你一定能理解👋

  • 使用 ViewBinding 前,MyFragment.kt 👇:
kotlin 复制代码
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

class MyFragment : Fragment() {
   
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_my, container, false)
    }
}
  • 使用 ViewBinding 后,MyFragment.kt 👇:

    kotlin 复制代码
    import android.os.Bundle
    import androidx.fragment.app.Fragment
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import com.example.mtes.databinding.FragmentMyBinding
    
    class MyFragment : Fragment() {
    
        private var binding: FragmentMyBinding? = null
    
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            binding = FragmentMyBinding.inflate(layoutInflater, container, false)
            val view = binding?.root
            return view
        }
    }

5.3 ViewHolder 中使用

列表也是我们常见的场景,使用 RecyclerView + Adapter + ViewHolder 实现列表,里面少不了对ViewHolder中的View的 findViewById。

比如列表item布局: layout_holder.xml 👇

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:id="@+id/tv_item"
        />
</LinearLayout>
  • 使用ViewHolder前,MyAdapter.kt👇:

    kotlin 复制代码
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import android.widget.TextView
    import androidx.recyclerview.widget.RecyclerView
    
    class MyAdapter: RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
    
        private val dataList: List<String>? = null
    
        class MyViewHolder(val itemView: View) : RecyclerView.ViewHolder(itemView) {
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_holder, parent, false)
            return MyViewHolder(view)
        }
    
        override fun getItemCount(): Int {
            return dataList?.size ?: 0
        }
    
        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            val tvText: TextView = holder.itemView.findViewById<TextView>(R.id.tv_item)
            tvText.text = "你好"
        }
    }
  • 使用ViewHolder后,MyAdapter.kt👇:

    kotlin 复制代码
    import android.view.LayoutInflater
    import android.view.ViewGroup
    import androidx.recyclerview.widget.RecyclerView
    import com.example.mtes.databinding.LayoutHolderBinding
    class MyAdapter: RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
    
        private val dataList: List<String>? = null
    
        class MyViewHolder(val binding: LayoutHolderBinding) : RecyclerView.ViewHolder(binding.root) {
    
        }
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            val binding = LayoutHolderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            return MyViewHolder(binding)
        }
    
        override fun getItemCount(): Int {
            return dataList?.size ?: 0
        }
    
        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.binding.tvItem.text = "标题"
        }
    }

6. ViewBinding的优点

与使用 findViewById 相比,视图绑定具有一些很显著的优点:

  • Null 安全
    由于 ViewBinding 会创建对布局中的 view 的直接引用,因此不存在因 view ID 找不到而引发 null 指针异常的风险.
  • 类型安全
    viewbinding 生成的属性类型和布局中的View类型是一致的,不存在之前findViewById后,类型转换的风险。

7. 与 dataBinding 对比

dataBinding 与 viewBinding 类似,也是可以生成绑定代码,但侧重点在于对于数据的赋值,相比 viewBinding 更复杂一些。因此如果只是想省略 findViewById ,那么推荐用 viewBinding 就好了,因为它有以下优势:

  • 加快编译速度:视图绑定不需要处理注解,因此编译时间更短。
  • 易于使用:视图绑定不需要特别标记的 XML 布局文件,因此在您的应用中采用的速度更快。在模块中启用视图绑定后,它会自动应用于该模块的所有布局。

另一方面,与 dataBinding 相比,viewBinding也有一些劣势:

  • viewBinding 不支持布局变量或布局表达式,因此它不能用于直接从 XML 布局文件声明动态界面内容。
  • viewBinding 不支持双向数据绑定。

最后,dataBinding 与 viewBinding 是可以同时使用的,在哪个页面用哪个,取决于你喽🤣。

怎么样,有了 ViewBinding,妈妈再也不用担心你的手指了,快去试试吧~

如果这篇文章对你有用,欢迎支持🙏

官网文档:https://developer.android.google.cn/topic/libraries/view-binding#groovy

相关推荐
踢球的打工仔4 小时前
PHP面向对象(7)
android·开发语言·php
安卓理事人4 小时前
安卓socket
android
安卓理事人10 小时前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学11 小时前
Android M3U8视频播放器
android·音视频
q***577411 小时前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober12 小时前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿12 小时前
关于ObjectAnimator
android
zhangphil13 小时前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我14 小时前
从头写一个自己的app
android·前端·flutter
lichong95115 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端