模块内 build.gradle 添加dataBinding支持
android{
......
dataBinding{
enabled = true
}
}
在布局 中 alt+回车 生成data binging layout 设置布局
<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内添加引用的model-->
<data>
<!-- 指定的数据源 name-别名 type-指关联的类 -->
<variable
name="model"
type="包名.model.LoginModel" />
<!-- 这样写也一样 -->
<import type="包名.model.LoginModel"/>
<variable
name="model_import"
type="LoginModel" />
<!-- 也可以使用内部类 来调用方法 在model内也可以 为了获取运行环境 在activity内写内部类 更方便 -->
<variable
name="click"
type="包名.ui.activity.LoginActivity.ClickLogin" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activity.LoginActivity">
<!-- 单项绑定 直接通过别名model获取 LoginModel里的数据-->
<!-- 通过别名click设置点击事件-->
<TextView
android:id="@+id/welcomeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:onClick="@{()->click.toLogin()}"
android:text="@{model.text}" />
<!-- 双向绑定 输入框输入后 text自动修改-->
<EditText
android:text="@={model.text}"
app:layout_constraintTop_toBottomOf="@id/welcomeText"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
LoginModel类
//继承ViewModel 或者 继承AndroidViewModel--> 主要看需不需要环境 因为点击事件已经通过Activity
//的内部类实现所以ViewModel够用 主要管理数据即可
public class LoginModel extends ViewModel {
//使用MutableLiveData包裹数据 可以实现数据改变之后布局内自动更改
private MutableLiveData<String> text;
public MutableLiveData<String> getText() {
if (text ==null){
text = new MutableLiveData<>();
text.setValue("");
}
return text;
}
public void setText(MutableLiveData<String> text) {
this.text = text;
}
}
//后面为LiveDate实现的源码 以及去解决数据粘性的地方 可不看
//可以直接点进去源码 当赋值时调用了 setValue 或者postValue -->postValue用于异步赋值
public class MutableLiveData<T> extends LiveData<T> {
public MutableLiveData(T value) {
super(value);
}
public MutableLiveData() {
super();
}
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
//点击 setValue 到父级LiVeData的setValue方法
@MainThread
protected void setValue(T value) {
assertMainThread("setValue"); //检查是否主线程
mVersion++;
mData = value;
dispatchingValue(null); //--去通知监听者
}
//点击进去 dispatchingValue
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
//这里去循环了所有的监听者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue()); //-->进入这里
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
//点击进去 considerNotify
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) { //如果想解决数据粘性问题 可以通过Hook去修改让这两个条件相等
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData); //这里通知了监听者
}
Activity内
public class LoginActivity extends BaseActivity {
private ActivityLoginBinding bind;
private LoginModelmodel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//通过DataBindingUtil设置ContentView 拿到对应的Binding类
bind = DataBindingUtil.setContentView(this,R.layout.activity_login);
//需要环境 继承 AndroidViewModel
// model = new ViewModelProvider(this,new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(LoginModel.class);
//不需要环境 继承 ViewModel
model = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(LoginModel.class);
//绑定数据Model
bind.setModel(model);
//绑定点击事件内部类
bind.setClick(new ClickLogin());
//建立感应
bind.setLifecycleOwner(this);
}
public class ClickLogin{
public void toLogin(){
Toast.makeText(mContext,"登录",Toast.LENGTH_SHORT).show();
}
}
}
我们的Activity继承自 AppCompatActivity 继承自 FragmentActivity 继承自 ComponentActivity
ComponentActivity实现了 ViewModelStoreOwner 和 LifecycleOwner 接口 所以可以直接传this