Jetpack系列(八) — Data Bidnding && View Binding
Hilt 简单介绍
初步印象
Data Bidnding
, 包含View Binding
所有功能,支持双向绑定
View Binding
仅仅支持绑定View
,kotlin-android-extensions
插件的替代方案
Data Bidnding
和View Binding
可以同时存在
Data Bidnding
性能劣于View Binding
, 因此一些项目当中仅仅使用View Binding
基本概念
我只打算使用
View Binding
替代findViewById()
,Data Bidnding
了解即可
基本使用
View Binding 基本使用
- 将
viewBinding
元素添加到其build.gradle
文件中
android {
...
viewBinding {
enabled = true
}
}
复制代码
-
在 Activity 中使用视图绑定
- 在 Activity 的
onCreate()
方法,调用生成的绑定类中包含的静态inflate()
方法 - 用
binding.控件Id
操作控件
// MainActivity class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 自动生成 binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) } } 复制代码
- 在 Activity 的
-
在 Fragment 中使用视图绑定
- 请在 Fragment 的
onCreateView()
方法中执行,调用生成的绑定类中包含的静态inflate()
方法
class DeepLinkFragment : Fragment() { private var _binding: FragmentDeepLinkBinding? = null private val binding get() = _binding!! private val mainViewModel: MainViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentDeepLinkBinding.inflate(inflater, container, false) return binding.root } override fun onDestroy() { super.onDestroy() _binding = null } } 复制代码
- 请在 Fragment 的
-
在Adapter中使用ViewBinding
- 通过绑定类
inflate
方法传入ViewHolder
// WordListAdapter.kt class WordListAdapter : ListAdapter<Word, WordViewHolder>(WORDS_COMPARATOR) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder = WordViewHolder.create(parent) override fun onBindViewHolder(holder: WordViewHolder, position: Int) { val item = getItem(position) holder.bind(item) } companion object { private val WORDS_COMPARATOR = object : DiffUtil.ItemCallback<Word>() { override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean = oldItem == newItem override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean = oldItem.word == newItem.word } } } class WordViewHolder(binding: ItemWordBinding) : RecyclerView.ViewHolder(binding.root) { private val textView: TextView = binding.textView fun bind(word: Word?) { textView.text = word?.word?:"" } companion object { fun create(parent: ViewGroup): WordViewHolder { val binding = ItemWordBinding.inflate(LayoutInflater.from(parent.context), parent, false) return WordViewHolder(binding) } } } 复制代码
- 通过绑定类
Data Binding 基本使用
-
修改
build.gradle
文件dataBinding { enabled = true } 复制代码
-
生成
data binding
布局,参见知识点三- 这里我实现一下点击刷新的效果
- 点击事件
onClick="@{()-> model.updateTaps()}"
<?xml version="1.0" encoding="utf-8"?> <layout 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"> <data> <variable name="model" type="com.huang.myapplication.viewmodel.MainViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/home_contain" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.main.home.HomeFragment"> <Button android:id="@+id/btn_add" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginStart="10dp" android:layout_marginTop="10dp" android:layout_marginEnd="10dp" android:text="@string/refresh" android:onClick="@{()-> model.updateTaps()}" app:layout_constraintHorizontal_weight="1" app:layout_constraintLeft_toRightOf="@+id/btn_next" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv_count" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="10dp" android:text="@{model.taps}" app:layout_constraintBottom_toBottomOf="@+id/tv_current_count" app:layout_constraintLeft_toRightOf="@+id/tv_current_count" app:layout_constraintTop_toTopOf="@+id/tv_current_count" /> </androidx.constraintlayout.widget.ConstraintLayout> </layout> 复制代码
-
再
viewmodel
当中观察数据class MainViewModel @Inject constructor( private val repository: WordRepository ) : ViewModel() { private var _tapCount = 0 private var _taps = MutableLiveData<String>("$_tapCount taps") val taps: LiveData<String> = _taps fun updateTaps() { _tapCount++ _taps.value = "$_tapCount taps" } } 复制代码
-
绑定视图
-
Activity生成
binding
视图类// 方式一: val binding: ActivityXxxBinding = DataBindingUtil.setContentView( this, R.layout.activity_main) // 方式二: val binding: ActivityXxxBinding = ActivityMainBinding.inflate(getLayoutInflater()) 复制代码
-
Fragment
、ListView
或RecyclerView
适配器中使用数据绑定项// 方式一: val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false) // 方式二: val listItemBinding = DataBindingUtil.inflate(layoutInflater,R.layout.list_item, viewGroup, false) 复制代码
-
可以使用
LiveData
对象作为数据绑定来源,自动将数据变化通知给界面,需要binding.lifecycleOwner = this
设置视图绑定类的生命周期class HomeFragment : Fragment() { private var _binding: FragmentHomeBinding? = null private val binding get() = _binding!! private lateinit var adapter: WordListAdapter private val mainViewModel: MainViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = DataBindingUtil.inflate(layoutInflater, R.layout.fragment_home,container, false) setHasOptionsMenu(true) binding.lifecycleOwner = this return binding.root } override fun onDestroy() { super.onDestroy() _binding = null } } 复制代码
-
相关知识点
知识点一:
ViewBinding
忽略文件
-
一旦启动了
ViewBinding
功能之后,Android Studio会自动为我们所编写的每一个布局文件都生成一个对应的Binding类 -
Binding类的命名规则是将布局文件按驼峰方式重命名后,再加上Binding作为结尾。
-
如果有些布局文件你不希望为它生成对应的Binding类,可以在该布局文件的根元素位置加入
tools:viewBindingIgnore="true"
<LinearLayout ... tools:viewBindingIgnore="true" > ... </LinearLayout> 复制代码
知识点二:
View Binding
中include
布局
-
View Binding
使用需要个include
增加id, 通过Id 查找<include android:id="@+id/includeTitle" layout="@layout/include_title" /> // InOutFragment.kt binding.includeTitle.toolbarTitle.text = "出入作业" 复制代码
知识点三:快速生成
Data binding
布局
alt + Enter
选择cover data to data biding layout
知识点四: 绑定表达式(
Data bidng
)
- 算术运算符
+ - / * %
- 符串连接运算符
+
- 逻辑运算符
&& ||
- 二元运算符
& | ^
- 一元运算符
+ - ! ~
- 移位运算符
>> >>> <<
- 比较运算符
== > < >= <=
(请注意,<
需要转义为<
) instanceof
- 分组运算符
()
- 字面量运算符 – 字符、字符串、数字、
null
- 类型转换
- 方法调用
- 字段访问
- 数组访问
[]
- 三元运算符
?:
知识五: 双向绑定 (
Data bidng
)
@={}
表示法(其中重要的是包含“=”符号)可接收属性的数据更改并同时监听用户更新