Android DataBing基础使用 +ViewModel 及setvalue过程及原理

模块内 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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值