美文网首页Google-IO
安卓ViewBinding详解

安卓ViewBinding详解

作者: 蓝不蓝编程 | 来源:发表于2021-08-17 19:56 被阅读0次

    背景

    之前我们通过Kotlin Android Extensions来访问布局文件中的元素,但是这个现在被废弃了,原因如下:

    1. 空安全:res下的任何id都可以被访问,有可能因访问了非当前Layout下的id而出错
    2. 兼容性:只能在kotlin中使用,java不能用
    3. 局限性:不能跨模块使用

    访问布局中元素方法

    1. findViewById
    2. ButterKnife
    3. DataBinding
    4. Kotlin Android Extensions
    5. ViewBinding

    ViewBinding

    2019年Google I/O大会上公布的一款Android视图绑定工具:ViewBinding。使用方式类似DataBinding,但相比DataBinding,ViewBinding是一个更轻量级、更纯粹的findViewById的替代方案。它具有如下优点:

    1. 类型安全: ViewBinding会基于布局中的View生成类型正确的属性。比如,在布局中放入了一个 TextView ,视图绑定就会暴露出一个 TextView 类型的属性供开发中使用。
    2. 空安全:ViewBinding会检测某个视图是否只在某些配置下存在,并依据结果生成带有 @Nullable 注解的属性,所以即使在多种配置下定义的布局文件,视图绑定依然能够保证空安全。
    3. ViewBinding生成的绑定类是一个Java类,并且添加了Kotlin注解,可以很好地支持 Java 和 Kotlin 两种编程语言。

    使用详解

    1. Activity中基础使用方式
    • 修改build.gradle文件
      在android节点下增加buildFeatures 信息,具体如下:
    android {
        ...
        buildFeatures {
            viewBinding = true
        }
    }
    

    如果是AndroidStudio4.0以下,使用:

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

    注意: 开启viewBinding后,所有布局文件都会生成对应的binding类,如果要让某些布局文件不生成binding,就在布局文件根节点加入:tools:viewBindingIgnore="true"

    • Activity中调用方式
    class MainActivity : AppCompatActivity() {
        private lateinit var binding: ActivityMainBinding
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            binding.textView1.text = "textView1"
        }
    }
    

    注意:ActivityMainBinding是根据布局文件activity_main.xml来生成的。

    • 代码变化点说明
      之前的setContentView(R.layout.activity_main)修改为了:
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
    

    访问布局文件中元素时,使用:binding.textView1这样的命名方式即可。

    1. 布局中引用其他布局
    • 主布局文件
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111111" />
    
        <include
            android:id="@+id/subView"
            layout="@layout/view_sub" />
    </LinearLayout>
    

    注意:必须要给被引用布局设置id属性。

    • 被引用布局文件view_sub.xml
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="222222" />
    </LinearLayout>
    
    • 调用方法
    binding.subView.textView2.text = "textView2"
    
    1. 引用merge布局
    • 主布局文件
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="111111" />
    
        <include layout="@layout/view_merge" />
    </LinearLayout>
    
    • 被引用布局文件view_merge.xml
    <merge xmlns:android="http://schemas.android.com/apk/res/android">
        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="333333" />
    </merge>
    
    • 调用方法
    class MainActivity : AppCompatActivity() {
        private lateinit var binding: ActivityMainBinding
        private lateinit var viewMergeBinding: ViewMergeBinding
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            viewMergeBinding = ViewMergeBinding.bind(binding.root)
            viewMergeBinding.textView3.text = "textView3"
        }
    }
    
    1. 在Activity基类中使用
    • 基类BaseActivity
    abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
        protected lateinit var binding: T
    
        abstract fun initBinding(): T
    
        abstract fun init()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            binding = initBinding()
            setContentView(binding.root)
            init()
        }
    }
    
    • 子类MainActivity
    class MainActivity : BaseActivity<ActivityMainBinding>() {
        override fun initBinding() = ActivityMainBinding.inflate(layoutInflater)
    
        override fun init() {
            binding.textView1.text = "textView1"
        }
    }
    
    1. Fragment用法
    • 布局文件
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_blue_light"
        android:gravity="center">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="第一个Fragment" />
    
    </LinearLayout>
    
    • 调用方式
    class FirstFragment : Fragment() {
        private var _binding: FragmentFirstBinding? = null
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            _binding =
                FragmentFirstBinding.inflate(LayoutInflater.from(container?.context), container, false)
            return _binding?.root
        }
    
        override fun onDestroyView() {
            _binding = null
            super.onDestroyView()
        }
    }
    
    1. Fragment基类用法
    • 布局文件同上
    • 调用方式
    class FirstFragment : BaseFragment<FragmentFirstBinding>() {
    
        override fun initBinding() = FragmentFirstBinding.inflate(layoutInflater)
    
        override fun init() {
            _binding?.textView1?.text="textView1"
        }
    }
    
    1. RecyclerView中使用
      篇幅有限,只列出有变化的Adapter类:
    class RvAdapter : RecyclerView.Adapter<RvAdapter.MyViewHolder>() {
        private var mDataList = mutableListOf<String>()
        private lateinit var mContext: Context
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            mContext = parent.context
            val itemBinding =
                ItemLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
            return MyViewHolder(mContext, itemBinding)
        }
    
        override fun onBindViewHolder(viewHolder: MyViewHolder, position: Int) {
            val data = mDataList[position]
            viewHolder.bind(data)
        }
    
        fun setData(dataList: List<String>) {
            mDataList.clear()
            mDataList.addAll(dataList)
            notifyDataSetChanged()
        }
    
        override fun getItemCount(): Int = mDataList.size
    
        class MyViewHolder(private var context: Context, private var itemBinding: ItemLayoutBinding) :
            RecyclerView.ViewHolder(itemBinding.root) {
            fun bind(data: String) {
                //更新UI上nameTv展示内容
                itemBinding.nameTv.text = data
                //设置点击事件
                itemBinding.root.setOnClickListener {
                    Toast.makeText(context, data, Toast.LENGTH_SHORT).show()
                }
            }
        }
    }
    

    关于我

    厦门大学计算机专业|华为八年高级工程师
    十年软件开发经验,5年编程培训教学经验
    目前从事编程教学,软件开发指导,软件类毕业设计指导。

    参考资料

    https://blog.csdn.net/qq_20521573/article/details/110278319
    https://weilu.blog.csdn.net/article/details/109557820
    https://www.jianshu.com/p/f284dd13b953

    相关文章

      网友评论

        本文标题:安卓ViewBinding详解

        本文链接:https://www.haomeiwen.com/subject/tiiibltx.html