zl程序教程

您现在的位置是:首页 >  其他

当前栏目

viewBinding的使用(记一次重构项目的过程)

2023-02-26 09:48:54 时间
  • 一、前言
  • 二、环境的配置
  • 三、view Binding 基本用法
    • 1. Activity 中的用法
    • 2. Fragment 中的用法
    • 3. Adapter 中的用法
    • 4.使用include包含布局的嵌套布局
  • 四、总结

一、前言

最近放寒假了,终于有空做项目了,想着把之前的一些项目重构一下,碰巧重构到 view Binding 这块,之前都是用 kotlin 的那个扩展,其实刚开始做项目的时候这个就已经废弃了,由于当时自己有点懒,没去学习这个新的代替方案,所以就成为一个历史遗留的问题,参考官方文档

view Binding 官方文档,这里只是针对目前使用的几个场景进行重构,其他未涉及的场景可以同理得出。

二、环境的配置

Android Studio 的版本至少需要3.6及以上

在build.gradle 配置文件下添加以下语句,不过现在的版本貌似是默认启用view Binding

android {
        ...
        viewBinding {
            enabled = true
        }
}

由于绑定类是创建布局文件即生成的,故想要忽略某个布局需要在根布局添加以下内容

<LinearLayout
        ...
        tools:viewBindingIgnore="true" >
        ...
</LinearLayout>

三、view Binding 基本用法

首先利用布局绑定的类进行创建一个对象,并对其进行初始化,然后就获得一个viewBinding的对象,用此对象进行获取布局所对应的view以及布局下的相关控件,首先说明一下自动生成的命名规则,自动去掉_空格等非字母字符,其他单词采取首字母大写的命名法则最后加个Binding结尾,举个例子

//布局名字
fragment_name.xml
//生成类名
FragmentNameBinding

binding自动调用布局里面的id也发生了一些变化,变成驼峰的命名法,同样会忽略掉非字母字符,举个例子

//布局里面某个控件的id
android:id="@+id/item_name"
//生成的变量名
FragmentNameBinding.itemName

1. Activity 中的用法

首先创建一个延迟初始化的binding变量,然后在创建activity时进行初始化,设置当前的view,只需用binding.root即可获取

    private lateinit var binding:FragmentNameBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = FragmentNameBinding.inflate(layoutInflater)
        setContentView(binding.root)
        ...
    }

2. Fragment 中的用法

这个和Activity差不多,就是初始化不一样,这边采用一种比较安全的策略使得binding在fragment内部不能被修改,binding的get方法为_binding的,外部可以改变binding的值,内部不行

private var _binding: ResultProfileBinding? = null

//断言binding非空
private val binding get() = _binding!!
override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    return binding.root
}

3. Adapter 中的用法

这个稍微麻烦一点,不过原理还是一样的,下面这个例子即可说明,针对那些使用findViewById进行了一些优化,这里涉及item的复用,注意变量的作用域范围,考虑binding的声明位置

class TestAdapter(private val fragment:Fragment,private val testList: List<Test>):RecyclerView.Adapter<TestAdapter.ViewHolder>(){
    
    //对于holder参数进行了改造
    inner class ViewHolder(binding: TestItemBinding):RecyclerView.ViewHolder(binding.root){
        val fundName = binding.name
    }

    
    //在这里进行binding的初始化,这里对bingding的赋值和fragment类似
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder{
        val binding = TestItemBinding.inflate(LayoutInflater.from(parent.context),parent,false)
        binding.root.setOnClickListener {
			val name = binding.name
        }
        return ViewHolder(binding)
    }

    //这里其实基本不需要改动,但却是用binding的用法进行的
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.name = "test"
    }

    override fun getItemCount() = testList.size
}

4.使用include包含布局的嵌套布局

这个刚开始也有点懵,官方文档好像没写,后来想想,包含布局不是也可以当成一个控件使用,所以最后采用在包含控件前添加id实现了调用

<ScrollView
   ...
    <LinearLayout
        ...
        <include
            android:id="@+id/basic"
            layout="@layout/basic"/>
    </LinearLayout>
	...
</ScrollView>
//如果上述布局名字是fragment_basic.xml,则采用下述方式获得layout的binding
val basic = FragmentBasicBinding.inflate(layoutInflater)
basic.basic
//这个即为layout basic的binding

当然还有更简单的想法,直接再定义一个layout所对应的binding,如果实在不会获取的话,跟上面几种情况类似就不过多说明了

四、总结

总体来讲这次重构是比较成功的,以前使用kotlin扩展虽然方便但是还是比较容易出错,尤其是不同布局采用相同的id名时经常弄错,用了view binding之后就不需要担心这个了,与视图相绑定,安全性大大提高,同时也简化了传统的获取id的方法,是一次比较愉快的重构。