概念

与MVVM

配置

android {
    ...
    dataBinding{
        enabled = true
    }
}

UI绑定

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable
            name="title"
            type="String" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout 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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">


        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{title}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

binding.setTitle("avcd");

事件绑定

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

        binding.setPresenter(new Presenter());
    }
    public class Presenter{

        public void onClick(){
            Toast.makeText(MainActivity.this,"click",Toast.LENGTH_SHORT).show();
        }
    }
<Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{()-> presenter.onClick()}"
            />

数据绑定原理

编译 - 处理layout文件 - 解析表达式 - java编译 - 解析依赖

运算符

include

viewstub

观察者模式

public class UserInfo extends BaseObservable {

    private String name;
    private String password;
    private Integer age;

    public void setName(String name) {
        this.name = name;
        notifyChange();
    }

    public void setPassword(String password) {
        this.password = password;
        notifyChange();
    }

    public void setAge(Integer age) {
        this.age = age;
        notifyChange();
    }
}


private UserInfo userInfo = new UserInfo();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);

        binding.setPresenter(new Presenter());
        binding.setUser(userInfo);

    }
    public class Presenter implements TextWatcher {

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            userInfo.setName(charSequence.toString());
        }

        @Override
        public void afterTextChanged(Editable editable) {

        }
    }
<layout>
    <data>
        <variable
            name="user"
            type="wang.ismy.databinding.UserInfo" />

        <variable
            name="presenter"
            type="wang.ismy.databinding.MainActivity.Presenter" />
    </data>
    <LinearLayout 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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onTextChanged="@{presenter::onTextChanged}"
            />

        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </LinearLayout>
</layout>

高级绑定

列表绑定

public class UserAdapter extends RecyclerView.Adapter<BindingViewHolder> {

    private final LayoutInflater layoutInflater;

    private List<UserInfo> userInfoList = new ArrayList<>();

    public UserAdapter(Context context) {
        layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    }

    @Override
    public int getItemViewType(int position) {

        return super.getItemViewType(position);
    }

    @NonNull
    @Override
    public BindingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        ViewDataBinding binding =
                DataBindingUtil.inflate(layoutInflater,R.layout.item_user,parent,false);

        return new BindingViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull BindingViewHolder holder, int position) {
        final UserInfo userInfo = userInfoList.get(position);
        holder.getBinding().setVariable(wang.ismy.databinding.BR.item,userInfo);
        holder.getBinding().executePendingBindings();

    }

    @Override
    public int getItemCount() {
        return userInfoList.size();
    }

    public void addAll(List<UserInfo> list){
        userInfoList.addAll(list);
    }

    public void add(UserInfo userInfo){
        userInfoList.add(userInfo);
        notifyItemInserted(userInfoList.size());
    }

    public void remove(){
        if (userInfoList.size() == 0) return;
        userInfoList.remove(0);
        notifyItemRemoved(0);
    }

}
public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder {

    private T binding;

    public BindingViewHolder(@NonNull T itemView) {
        super(itemView.getRoot());
        binding = itemView;
    }

    public T getBinding() {
        return binding;
    }
}
binding = DataBindingUtil.setContentView(MainActivity.this,R.layout.activity_main);
        binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
        userAdapter = new UserAdapter(getApplicationContext());
        binding.setPresenter(new Presenter());
        binding.recyclerView.setAdapter(userAdapter);

        userAdapter.addAll(Arrays.asList(new UserInfo("1"),
                new UserInfo("2"),new UserInfo("3"),
                new UserInfo("4")));

自定义属性

@BindingAdapter({"app:imageUrl","app:placeholder"})
    public static void loadImage(ImageView view,
                                 String url, Drawable drawable
                                 ){
        Glide.with(view.getContext())
                .load(url)
                .placeholder(drawable)
                .into(view);
    }

binding.setUrl(url);
<layout>
    
    <data>
        <variable
            name="url"
            type="String" />
    </data>

    <LinearLayout 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"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <ImageView
            android:layout_width="150dp"
            android:layout_height="150dp"
            app:imageUrl="@{url}"
            app:placeholder="@{@drawable/ic_launcher_foreground}"
            />

    </LinearLayout>
</layout>

双向绑定

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={model.username}"
            />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={model.password}"
            />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{model.toString()}"
            />

表达式链


<data>

        <import type="android.view.View" />

</data>

<EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={model.username}"
            android:visibility="@{model.username.length() != 5 ?View.VISIBLE:View.GONE}"
            />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={model.password}"
            android:visibility="@{username.visibility}"
            />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{model.toString()}"
            android:visibility="@{username.visibility}"
            />

隐式更新

        <CheckBox
            android:id="@+id/checkbox"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@={model.username}"
            android:visibility="@{checkbox.checked ?View.VISIBLE:View.GONE}"
            />

Lambda表达式

<Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{model.toString()}"
            android:visibility="@{username.visibility}"
            android:onClick="@{()->presenter.click()}"
            />

动画

        binding.addOnRebindCallback(new OnRebindCallback() {
            @Override
            public boolean onPreBind(ViewDataBinding binding) {

                ViewGroup viewGroup = (ViewGroup) binding.getRoot();
                TransitionManager.beginDelayedTransition(viewGroup);

                return true;
            }
        });