概念
与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);
}
}
- 创建holder
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()}"
/>
动画
- Transition
binding.addOnRebindCallback(new OnRebindCallback() {
@Override
public boolean onPreBind(ViewDataBinding binding) {
ViewGroup viewGroup = (ViewGroup) binding.getRoot();
TransitionManager.beginDelayedTransition(viewGroup);
return true;
}
});