安卓开发中的ViewBinding使用
在安卓开发中ViewBinding的使用
目录
使用前提
在使用ViewBinding前要在build.gradle工程模块中加入如下配置:
android {
...
buildFeatures {
viewBinding = true
}
...
}
在加入上述配置后Android Studio会自动为每一个布局文件都生成一个对应的Binding类。
Binding类的命名规则是将布局文件按驼峰方式重命名后,再加上Binding作为结尾。
例如:
activity_main.xml布局对应的Binding类就是ActivityMainBinding类
fragment_main.xml布局对应的Binding类就是FragmentMainBinding类
一、在Activity中使用
假设在activity_main.xml的布局文件中有一个名为ButtonSubmit的Button控件,现在要为这个Button控件设置监听
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_main)
//加载布局,并获取布局中的元素引用
//LayoutInflater是一个用于从XML布局文件中实例化布局的类。
//它能够将XML布局文件转换为实际的视图对象
val binding = ActivityMainBinding.inflate(layoutInflater)
//通过 binding.root 获取布局的根视图
setContentView(binding.root)
//binding.ButtonSubmit使用Button控件
binding.ButtonSubmit.setOnClickListener{
//添加点击事件的处理逻辑
}
}
}
如果要在onCreate函数之外使用控件,需要将binding声明成全局变量,如下:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.ButtonSubmit.setOnClickListener{
//添加点击事件的处理逻辑
}
}
override fun onDestroy() {
super.onDestroy()
binding.ButtonSubmit.setOnClickListener{
//添加点击事件的处理逻辑
}
}
}
二、在Fragment中使用
方法一:
class MainFragment : Fragment() {
// 使用可空类型定义一个私有的_binding变量,用于存储FragmentMainBinding的实例
private var _binding: FragmentMainBinding? = null
// 定义一个绑定的属性访问器,它返回一个非空的FragmentMainBinding实例。
private val binding get() = _binding!!
// 使用FragmentMainBinding.inflate方法从给定的LayoutInflater和可选的容器中加载布局。
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentMainBinding.inflate(inflater, container, false)
return binding.root
}
override fun onDestroyView() {
// 首先调用super.onDestroyView(),以确保Fragment的基类也执行其销毁逻辑
super.onDestroyView()
// 将_binding设置为null,释放与视图绑定相关的资源
_binding = null
}
}
方法二:
class MainFragment : Fragment(R.layout.fragment_main) {
private lateinit var binding: FragmentMainBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 使用ViewBinding.inflate()方法来加载布局
binding = FragmentMainBinding.inflate(layoutInflater)
// 将binding.root添加到Fragment的视图中
view = binding.root
// 现在可以使用binding对象来访问布局中的元素
binding.exampleTextView.text = "Hello, ViewBinding!"
// 为按钮设置点击事件
binding.exampleButton.setOnClickListener {
// 按钮点击事件的处理逻辑
}
}
}
这两种方法都是使用ViewBinding在Fragment中绑定布局
1、绑定初始化时机:
第一种方法:在onCreateView中初始化ViewBinding。这是Fragment生命周期中创建视图的阶段,适合在视图创建时立即绑定。
第二种方法:在onViewCreated中初始化ViewBinding。这是Fragment视图创建后,但尚未设置任何额外的视图设置之前,适合在视图创建之后进行绑定。
2、视图返回方式:第一种方法:直接返回binding.root作为onCreateView的结果。这意味着Fragment的根视图是通过ViewBinding生成的。
第二种方法:在onViewCreated中将binding.root赋值给view参数。这通常发生在Fragment的视图已经通过其他方式(例如,直接使用R.layout.fragment_example)创建之后。
3、视图销毁处理:第一种方法:在onDestroyView中将_binding设置为null,以避免内存泄漏。这是因为Fragment可能被重用,所以需要在视图销毁时清理绑定。
第二种方法:通常不需要在onDestroyView中进行特殊处理,因为lateinit的binding会在onDestroyView之前自动清理。
4、类型安全访问:第一种方法:使用_binding!!来强制访问绑定对象,这需要确保_binding在使用前已经被初始化。
第二种方法:使用lateinit var声明binding,这确保了binding在使用前已经被初始化,并且是不可空的。
三、在Adapter中使用
我们定义fruit_item.xml来作为RecyclerView子项的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="60dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/fruitImage"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/fruitName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="10dp"/>
</LinearLayout>
</LinearLayout>
编写不用ViewBinding的Adapter来加载和显示这个子项布局:
package com.example.recyclerviewtest
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplicationtestexample.R
class FruitAdapter(val fruitList: List<Fruit>) :
RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val fruitImage: ImageView = view.findViewById(R.id.fruitImage)
val fruitName: TextView = view.findViewById(R.id.fruitName)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.fruit_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val fruit = fruitList[position]
holder.fruitImage.setImageResource(fruit.imageId)
holder.fruitName.text = fruit.name
}
override fun getItemCount() = fruitList.size
}
具体细节实现可移步:
RecyclerView的实现http://t.csdnimg.cn/5zWcA
编写使用ViewBinding的Adapter来加载和显示这个子项布局:
class FruitAdapter(val fruitList: List<Fruit>) : RecyclerView.Adapter<FruitAdapter.ViewHolder>() {
//让ViewHolder的构造函数接收FruitItemBinding这个参数
//ViewHolder的父类RecyclerView.ViewHolder只会接收View类型的参数
//因此需要调用binding.root获得fruit_item.xml中根元素的实例传给RecyclerView.ViewHolder
inner class ViewHolder(binding: FruitItemBinding) : RecyclerView.ViewHolder(binding.root) {
val fruitImage: ImageView = binding.fruitImage
val fruitName: TextView = binding.fruitName
}
//调用FruitItemBinding的inflate()函数去加载fruit_item.xml布局文件
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = FruitItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val fruit = fruitList[position]
holder.fruitImage.setImageResource(fruit.imageId)
holder.fruitName.text = fruit.name
}
override fun getItemCount() = fruitList.size
}
这段代码的核心基本都在onCreateViewHolder()函数和ViewHolder函数当中。
这样就不需要再使用findViewById()函数来查找控件实例了,而是调用binding.fruitImage和binding.fruitName就可以直接引用到相应控件的实例。
四、在引入布局中使用
假设我们有如下example.xml布局,是希望作为一个通用布局引入到各布局当中的:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/exampleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Example"
android:textSize="20sp" />
</RelativeLayout>
假设需要在 activity_main.xml 布局中引入该布局,我们这样引入:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
...
<include
android:id="@+id/example"
layout="@layout/example" />
...
</LinearLayout>
然后可以直接在MainActivity文件中使用example.xml布局的控件
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.example.exampleTextView.text = "Title"
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)