这里写自定义目录标题
Android DataBinding 使用步骤
Step1
plugins {
id 'kotlin-kapt'
}
#....
buildFeatures {
dataBinding true
}
dependencies {
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
// Lifecycles only (without ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
}
Step 2
此时使用binding layout
之后,该layout会以 <layout>
tag包裹住 , 假设该xml的名称为:fragment_first.xml
<layout xmlns: android="xxxxx">
<data class="FragmentFirst111DataBinding">
<variable
name="myViewModel"
type="package.to.MyViewModel"/>
</data>
<原有Layout>
<TextView android:text="@{myViewModel.text}"/>
<Button android:onClick="@{() -> myViewModel.click()}"/>
</原有Laout>
</layout>
Step 4
接下来创建对应的ViewModel类, 以及一个ViewModelFactory以增加拓展性,并且将ViewModel和Fragment绑定起来
实现ViewModelFactory.Factory接口
接口如下
/**
* Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
*/
public interface Factory {
/**
* Creates a new instance of the given {@code Class}.
* <p>
*
* @param modelClass a {@code Class} whose instance is requested
* @param <T> The type parameter for the ViewModel.
* @return a newly created ViewModel
*/
@NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
具体的实现:
这里目的是为了给ViewModel传递参数,默认的ViewModelProvider只是提供了一个default的无参数的factory,主要关注modelClass.newInstance()
的实现
public static class NewInstanceFactory implements Factory {
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
接下来由我们自行实现factory并传入参数到ViewModel中
class FirstViewModelFactory(private var app: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(FirstViewModel::class.java)) {
return FirstViewModel(app) as T
}
throw IllegalArgumentException("Unknown ViewModel Class")
}
}
将ViewModel 和Fragment绑定起来
private lateinit var viewModel:FistVieModel
private lateinit var viewModelFactory:FistViewModelFactory
// 注意这里的FragmentFirst111DataBinding 有如下两种方式
/*
* - type_filed.xml --> TypeFiledDataBinding(分为两部分: TypeFiled + DataBinding)
* - 直接由<data class="FragmentFirst111DataBinding"> 指定.
*/
private lateinit var dataBinding: FragmentFirst111DataBinding
// some code snippet
viewModelFacotry = FistViewModelFactory(requireActivity().application)
// 这里的DataBindingUtil是由 buildFeature.dataBinding = true 引入的
dataBinding = DataBindingUtil.inflate(/*same as before....*/)
viewModel = ViewModelProvider(this,viewModelFactory).get(FirstViewModel::class.java)
// 这里将xml中的fistViewModel 和上一行viewModel 关联起来
dataBinding.fistViewModel = viewModel
dataBinding.lifecycleOwner = this
// 返回被layout包裹的ViewGroup
return dataBindign.root
查看ViewModel的具体实现
这里需要注意下LiveData 和MutableLiveData的区别.在下一篇中在细讲
class FirstViewModel(val app: Application) : AndroidViewModel(app) {
// The TextView
private var _text: MutableLiveData<String> = MutableLiveData<String>()
val text: LiveData<String> get() = _text
fun setText() {
_text.value = "From ViewModel Clicked"
}
}
当我们点击 button的时候,会将ViewModel中的text值更新,进而更新到界面上来.