一剃法、基本的使用姿勢
1. module的build.gradle文件加上一行配置代碼
android {
? ? ...? ? dataBinding {
? ? ? ? enabled = true
? ? }}
2. 創(chuàng)建布局文件
只需要在之前布局的基礎(chǔ)上试溯,外層嵌套 即可艾少。
? ? ? ? ? ? name="student"
? ? ? ? ? ? type="com.xiaweizi.bean.Student"/>
? ? ? ? ? ? ? ? name="student"
? ? ? ? ? ? ? ? type="Student"/>
? ? ? ? -->
? ? ? ? android:layout_width="match_parent"
? ? ? ? android:layout_height="match_parent"
? ? ? ? android:gravity="center_horizontal"
? ? ? ? android:orientation="vertical">
因?yàn)閄ML是不支持自定義導(dǎo)包的驳阎,所以通過import先導(dǎo)包,如果類名相同的話可以通過alias進(jìn)行區(qū)分:
? ? ? ? alias="MyView"/>
? ? name="view1"
? ? type="View"/>
? ? name="view2"
? ? type="MyView"/>
這個時候會在app\build\generated\source\debug\包名路徑下生成對應(yīng)的binding類,命名方式囱皿,舉個例子最為直接:
原XML名:activity_main? ----> 生成對應(yīng)的binding名: ActivityMainBinding
3. Activity中替換原來的setContentView()代碼
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
二哗魂、事件的binding
1.單向binding
案例1:(view id)
? ? android:id="@+id/tv_content"
? ? android:text="@{student.name}"
? ? android:layout_width="match_parent"
? ? android:layout_height="50dp"/>
在代碼中通過binding直接可以獲取到這個TextView
mBinding.tvContent
案例2:(click event)
①定義按鍵處理的類型
public class Presenter {
? ? ? //Android標(biāo)準(zhǔn)的事件類型肛走,需要注意Method中的參數(shù)和api中的保持一致
public void onTextChanged(CharSequence s, int start, int before, int count) {
? ? ? ? ? ? employee.setFirstName(s.toString());
? ? ? ? ? ? employee.setFired(!employee.isFired.get());
? ? ? ? ? ? //binding.setEmployee(employee);
? ? ? ? }
//自定義的事件類型
? ? ? ? public void onClickListenerBinding(Employee employee) {
? ? ? ? ? ? Toast.makeText(SimpleActivity.this, employee.getLastName(),
? ? ? ? ? ? ? ? ? ? Toast.LENGTH_SHORT).show();
? ? ? ? }
? ? }
②、在xml中聲明制定的案件處理的類型和指定事件
? ? ? ? ? ? name="presenter"
? ? ? ? ? ? type="com.github.markzhai.sample.SimpleActivity.Presenter"/>
//Android標(biāo)準(zhǔn)的事件類型
? ? ? ? ? ? android:id="@+id/et_first_name"
? ? ? ? ? ? android:layout_width="match_parent"
? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? android:hint="輸入 First Name jiaoyin"
? ? ? ? ? ? android:onTextChanged="@{presenter::onTextChanged}"/>
//自定義的事件類型
? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? android:layout_marginLeft="5dp"
? ? ? ? ? ? android:onClick="@{() -> presenter.onClickListenerBinding(employee)}"
? ? ? ? ? ? android:text="@{employee.lastName}"/>
2.雙向binding
之前說的單向綁定录别,即當(dāng)數(shù)據(jù)變化朽色,通過mBinding.setStudent(student)方式驅(qū)動UI的改變
而雙向綁定,無論View還是ViewModel誰改變组题,都會驅(qū)動另一方的改變葫男,實(shí)現(xiàn)雙向綁定有兩種方式:繼承BaseObservable或者使用ObservableField創(chuàng)建成員變量。
案例1:繼承BaseObservable:
public class Employee extends BaseObservable {
? ? private String mLastName;
? ? private String mFirstName;
? ? public Employee(String lastName, String firstName) {
? ? ? ? mLastName = lastName;
? ? ? ? mFirstName = firstName;
? ? ? ? isFired.set(false);
? ? }
? ? @Bindable
? ? public String getLastName() {
? ? ? ? return mLastName;
? ? }
? ? public void setLastName(String lastName) {
? ? ? ? mLastName = lastName;
? ? ? ? notifyPropertyChanged(com.github.markzhai.sample.BR.lastName);
//notifyChange();
? ? }
}
這個時候當(dāng)調(diào)用setLastName()方法,不僅數(shù)據(jù)改變往踢,UI中的TextView內(nèi)容也會隨之改變腾誉。
我們可以發(fā)現(xiàn)有兩個方法:notifyPropertyChanged()和notifyChange,一個是更新指定的變量,第二個是更新所有該ViewModel中的對象峻呕。
而notifyPropertyChanged(int fieldId)里面?zhèn)鞯膮?shù)利职,即上面通過@Bindable注解創(chuàng)建對應(yīng)的變量id。
案例2:使用ObservableField創(chuàng)建成員變量
public class Employee extends BaseObservable {
? ? private String mLastName;
? ? private String mFirstName;
? ? public ObservableArrayMap user = new ObservableArrayMap<>();
? ? private String mAvatar;
? ? public ObservableBoolean isFired = new ObservableBoolean();
? ? public Employee(String lastName, String firstName) {
? ? ? ? mLastName = lastName;
? ? ? ? mFirstName = firstName;
? ? ? ? isFired.set(false);
? ? }
? ? public void setFired(boolean fired) {
? ? ? ? isFired.set(fired);
? ? }
? ? @Bindable
? ? public String getAvatar() {
? ? ? ? return mAvatar;
? ? }
? ? public void setAvatar(String avatar) {
? ? ? ? mAvatar = avatar;
? ? }
}
通過使用ObservableField創(chuàng)建的對象作用相當(dāng)于第一種的方案瘦癌,支持ObservableInt猪贪、ObservableBoolean或者是ObservableField指定的類型、ObservableArrayMap讯私、ObservableArrayList等热押。
ObservableField內(nèi)部已經(jīng)封裝了get和set方法,如果成員變量是public屬性斤寇,直接通過
mStudent.name.set("shabi");
String name = mStudent.name.get();
設(shè)置和獲取對應(yīng)的成員變量的值桶癣。
其他用法:
2.?ViewStub和include
dataBinding同樣是支持ViewStub的,使用起來也很簡單娘锁,直接貼代碼了牙寞。
? ? android:id="@+id/view_stub"
? ? android:layout_width="wrap_content"
? ? android:layout_height="wrap_content"
? ? android:layout="@layout/viewstub"/>
代碼中:
View inflate = binding.viewStub.getViewStub().inflate();
inflate即為替代ViewStub的View.
至于include更簡單,用法跟以前是差不多莫秆,唯一不同的是可以將ViewModel傳到下一個XML中:
bind:student="@{student}"/>
layout_include中同樣可以共享student這個對象间雀。
3.??@BindingConversion
dataBinding還支持對數(shù)據(jù)的轉(zhuǎn)換,或者是類型的轉(zhuǎn)換
4.自定義的屬性之BindingAdapter的使用
案例:
//1镊屎、xml定義
android:id="@+id/username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="35sp"
android:text="@{user.name}"/>
//2惹挟、BindingAdapter自定義
public class TextViewBindingAdapter {
@BindingAdapter("android:text")
public static voidsetText(TextView view, CharSequence text) {
? ? ? ? final CharSequence oldText = view.getText();
? ? ? ? if (text == oldText || (text == null && oldText.length() == 0)) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? if (text instanceof Spanned) {
? ? ? ? ? ? if (text.equals(oldText)) {
? ? ? ? ? ? ? ? return; // No change in the spans, so don't set anything.
? ? ? ? ? ? }
? ? ? ? } else if (!haveContentsChanged(text, oldText)) {
? ? ? ? ? ? return; // No content changes, so don't set anything.
? ? ? ? }
? ? ? ? view.setText(text);
? ? }
}
//3、更新User的name的值
User user = new User(name, age);
mBinding.setUser(user);
databinding框架缝驳,會做如下幾件事情:
①計(jì)算出@{user.name} 表達(dá)式的值连锯;
②尋找合適的BindingAdapter归苍,如果找到,就調(diào)用它對應(yīng)BindingAdapter里面的(setText)方法运怖;
③如果沒有找到合適的BindingAdapter霜医,就在View上尋找合適的(setText)方法調(diào)用;
如此類推驳规,可以自定義BindingAdapter..............
5. DataBindingComponent
通過BindingAdapter是可以增加一些自定義的屬性或者是修改Android原生的屬性,但是它有一個弊端署海,就是全局修改所有的相關(guān)屬性吗购,不過配合上DataBindingComponent就可以解決這個問題。
6.RecyclerView中的應(yīng)用
案例:
//xml定義部分:
? ? xmlns:android="http://schemas.android.com/apk/res/android">
? ? ? ? ? ? name="presenter"
? ? ? ? ? ? type="com.github.markzhai.sample.ListActivity.Presenter"/>
? ? ? ? android:layout_width="match_parent"
? ? ? ? android:layout_height="match_parent"
? ? ? ? android:orientation="vertical">
? ? ? ? ? ? android:id="@+id/recycler_view"
? ? ? ? ? ? android:layout_width="match_parent"
? ? ? ? ? ? android:layout_height="match_parent"/>
//初始化 recycleview 和 adapter部分
protected void onCreate(@Nullable Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? mBinding = DataBindingUtil.setContentView(this, R.layout.activity_list);
? ? ? ? mBinding.setPresenter(new Presenter());
mBinding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
mEmployeeAdapter = newEmployeeAdapter(this);
mBinding.recyclerView.setAdapter(mEmployeeAdapter);
? ? ? ? List demoList = new ArrayList<>();
? ? ? ? demoList.add(new Employee("Zhai", "Mark", false));
? ? ? ? demoList.add(new Employee("Zhai2", "Mark2", false));
? ? ? ? demoList.add(new Employee("Zhai3", "Mark3", true));
? ? ? ? demoList.add(new Employee("Zhai4", "Mark4", false));
mEmployeeAdapter.addAll(demoList);
? ? }
//自定義viewholder部分
public class BindingViewHolder
? ? ? ? extends RecyclerView.ViewHolder {
? ? private T mBinding;
? ? public BindingViewHolder(T binding) {
//注意砸狞,這里是要設(shè)置 binding的rootview 給到viewholder中
? ? ? super(binding.getRoot());
? ? ? ? mBinding = binding;
? ? }
? ? public T getBinding() {
? ? ? ? return mBinding;
? ? }
}
//自定義adapter部分
public class EmployeeAdapter extends RecyclerView.Adapter {
@Override
? ? public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
? ? ? ? ViewDataBinding binding;
? ? ? ? if (viewType == ITEM_VIEW_TYPE_ON) {
//加載出 DataBinding的對象
binding =DataBindingUtil.inflate(mLayoutInflater,
? ? ? ? ? ? ? ? ? ? R.layout.item_employee, parent, false);
? ? ? ? } else {
binding =DataBindingUtil.inflate(mLayoutInflater,
? ? ? ? ? ? ? ? ? ? R.layout.item_employee_off, parent, false);
? ? ? ? }
//注意
returnnew BindingViewHolder(binding);
? ? }
? ? @Override
? ? public void onBindViewHolder(BindingViewHolder holder, int position) {
? ? ? ? final Employee employee = mEmployeeList.get(position);
//注意:
//設(shè)置 variable變量捻勉,并內(nèi)部有去做 notifyDataChange的動作
? ? ? ? holder.getBinding().setVariable(com.github.markzhai.sample.BR.item, employee);
//execute,以便馬上更新
? ? ? ? holder.getBinding().executePendingBindings();
? ? }