通過本文可以了解到的內(nèi)容:
1.如何使用dataBinding;
2.設置點擊事件(含參數(shù)的);
3.數(shù)據(jù)與UI同步更新;
4.基本的dataBinding語法;
5.自定義注解。
按照官網(wǎng)的文檔一步一步來學習
官方文檔傳送門
簡單開始
第一步,在module的build.gradle文件中添加如下代碼,注意是android節(jié)點下添加:
android {
...
dataBinding {
enabled = true
}
}
第二步,增加一個數(shù)據(jù)實體類。
public class UserBean{
private String firstName;
public UserBean(String firstName) {
this.firstName = firstName;
}
}
第三步,修改layout文件,以layout節(jié)點開始,data節(jié)點包含數(shù)據(jù)實體類,其他就和以前布局文件沒有啥區(qū)別。
給某個textview綁定數(shù)據(jù):android:text="@{user.firstName}",user就是某個實體類在這個文件中的引用名,firstName為這個實體類的某個屬性。
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
// 以下類在本xml文件中的引用名稱
name="user"
// 數(shù)據(jù)實體類全名
type="com.hotelgg.android.hotelggreview.data.UserBean" />
<variable
name="person"
type="com.hotelgg.android.hotelggreview.data.PersonBean"/>
<variable
name="onclick"
type="com.hotelgg.android.hotelggreview.handler.ClickHandler"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/main_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/red_2"
android:padding="10dp"
android:text="@{user.firstName}"
android:onClick="@{onclick.onClick}"
android:textColor="@color/white_1" />
<TextView
android:id="@+id/person_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/red_2"
android:layout_marginTop="20dp"
android:padding="10dp"
android:text="@{person.name}"
android:onClick="@{onclick.onClick}"
android:textColor="@color/white_1" />
</LinearLayout>
</layout>
第四步,在activity中的使用,ActivityMainBinding的命名規(guī)則是和其綁定的xml文件的命名規(guī)則相關的,例如,activity_main為xml文件的名稱,那么就在其后面增加一個binding,首字母大寫即可。
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
UserBean userBean = new UserBean("shuai bu shuai");
binding.setUser(userBean);
坑Num.1
注意ActivityMainBinding這個類,編譯器不會自動編譯出來,需要build一下項目這個類才能夠被引用到。
坑Num.2
From the perspective of data binding, these two classes are equivalent.
這是官網(wǎng)的一段話,我來斷章取義一下,第一句話不知道怎么翻譯,什么鬼從data binding的透明(還能穿透明裝呢)?申明來看?(知道的朋友指點一下)第二句,這兩個類是等同的。然后我就跟著官方文檔一樣就寫了一個數(shù)據(jù)model的構造器。
public class UserBean{
private String firstName;
public UserBean(String firstName) {
this.firstName = firstName;
}
}
編譯,啪!不出意外,你已經(jīng)得到了ide的一個異常
Error:(31, 29) Could not find accessor com.hotelgg.android.hotelggreview
.data.UserBean.firstName
應該添加一個get方法的入口,所以不知道官方文檔說的這兩者是等同的是嘛意思!
public class UserBean{
private String firstName;
public UserBean(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
}
添加點擊事件
第一步,添加一個ClickHandler類,名字隨便取。
public class ClickHandler {
private BaseActivity context;
private ActivityMainBinding mDataBinding;
public ClickHandler(BaseActivity context, ActivityMainBinding mDataBinding) {
this.context = context;
this.mDataBinding = mDataBinding;
}
public void onClick(View view) {
if (R.id.main_tv == view.getId()) {
UserBean bean = mDataBinding.getUser();
bean.setFirstName("perry");
} else if (R.id.person_name == view.getId()) {
// 這里先不用理會
PersonBean bean = mDataBinding.getPerson();
bean.name.set("mary");
}
}
}
第二步,在activity中添加綁定
binding.setOnclick(new ClickHandler(this, binding));
第三步,對應的xml中添加引用,上面已經(jīng)給出完整代碼。
<data>
<variable
name="onclick"
type="com.hotelgg.android.hotelggreview.handler.ClickHandler"/>
</data>
// textview添加點擊事件
android:onClick="@{onclick.onClick}"
然后,就沒有然后了,可以運行開干了。
點擊事件中傳遞參數(shù)
這種場景主要應用于:一個recyclerview的item在點擊時需要取出當前item的數(shù)據(jù),比如一個當前item的id或者url要傳遞到下一個頁面中去。這個時候從綁定的數(shù)據(jù)中取出這個參數(shù)也有相應的辦法。
<data>
<import type="com.hotelgg.android.hotelggreview.adapter.UserAdapter.UserAdapterItemClick" />
<variable
name="hotelInfo"
type="com.hotelgg.android.hotelggreview.data.HotelInfoBean" />
<variable
name="itemClick"
type="UserAdapterItemClick" />
</data>
// 某個控件的點擊方法,其實就是lambda表達式的形式
android:onClick="@{()->itemClick.onClick(hotelInfo)}"
然后在adapter中進行相應的注冊,這里涉及到在recyclerview當中使用,具體的代碼會在后頭貼出。這里只是簡單的演示。
((ItemSingleTextBinding) binding).setItemClick(new UserAdapterItemClick());
public static class UserAdapterItemClick {
public void onClick(HotelInfoBean bean) {
LogUtil.e(bean.title.get());
bean.title.set("change big hotel");
}
}
這里有一點小小的觀點需要表達一下:我們可以把這里的UI這樣理解,它有自身的數(shù)據(jù)源model,有自身的操作行為handler,而同一個頁面,我更加傾向于讓其使用一個handler,這樣復用性高一些,至于每個控件的數(shù)據(jù)源,我們可以通過傳遞進來的ActivityMainBinding對象進行獲取和改變,UI層面就不需要做除了初始化之外的其他任何工作。所有的邏輯操作全由handler進行。
雖然點擊事件和數(shù)據(jù)綁定都已經(jīng)完成,但是數(shù)據(jù)綁定后,改變數(shù)據(jù)源是不是就能夠直接讓UI發(fā)生相應的更新變化呢?答案是否定的。
數(shù)據(jù)源與UI同步更新
如果想要改變數(shù)據(jù)源后同步更新UI界面,就需要對數(shù)據(jù)源進行一定的修改,我們還是以UserBean為例。
第一種方法
繼承BaseObservable,然后在get方法上加上@Bindable注解,在set方法中加入notifyPropertyChanged(BR.firstName);進行數(shù)據(jù)更新。這個BR有點類似于資源文件引用中的R,也是包名.BR。
public class UserBean extends BaseObservable{
private String firstName;
private int num;
public UserBean(String firstName, int num) {
this.firstName = firstName;
this.num = num;
}
@Bindable
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
notifyPropertyChanged(BR.num);
}
@Bindable
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
}
第二種方法
用Google給我們提供的Observable...類,支持所有數(shù)據(jù)類型。
public class PersonBean {
public ObservableField<String> name = new ObservableField<>();
public ObservableField<String> lastName = new ObservableField<>();
}
// 更新方式
personBean.lastName.set("White");
一些基本的語法
增加默認值
除了指定相應的綁定數(shù)據(jù)對象外,還可以增加默認值,如下:
android:text="@{user.firstName,default=test}"
數(shù)據(jù)類型轉換
類型的轉換,把int型轉化成string類型并進行存儲,其中int值還可以進行相應的計算。
android:text="@{String.valueOf(user.num + 1)}"
使用資源文件屬性
還可以指定資源文件中的屬性,并且直接使用占位符的形式來填充數(shù)據(jù)(這個功能強大)。
android:text="@{@string/name_format(person.name,person.lastName)}"
<resources>
<string name="name_format">第一個:%s,第二個:%s</string>
</resources>
使用三目運算符
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
不過注意,在導入集合類型時,咱們一般都會使用泛型類,以下泛型類為string類型,因為是基本數(shù)據(jù)類型,所以不用導入。使用泛型類的格式如下:
<data>
<import type="java.util.List"/>
<variable name="list" type="List<String>"/>
</data>
自定義注解
這個功能相當之強大,廢話不多說,直接上代碼。先做一個工具類,名字隨便取,如我的AppBindingUtils,具體啥意思,注釋當中已經(jīng)說的很清楚。
public class AppBindingUtils {
// BindingAdapter注解,自定義注解,可以讓某些控件增加自定義屬性,并且,只要在xml中出現(xiàn)該屬性,
// 就會調(diào)用該注解注釋的方法。
// 其中 bind_data 為xml中自定義屬性的屬性名,setDataTest這個名字隨便取。
// 不讓recyclerView每次都設置adapter,這樣會刷新多余數(shù)據(jù)
@BindingAdapter("bind_data")
public static void setDataTest(RecyclerView recyclerView, ObservableArrayList<MultipleListBean> data) {
if (recyclerView != null && recyclerView.getAdapter() == null) {
recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext(), LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(new UserAdapter(data));
}
}
}
xml布局文件中如下,這樣,當編譯器發(fā)現(xiàn)了xml中有一項自定義注解編注的屬性時,就會帶著這個屬性去找有@BindingAdapter注解編注過并且屬性名為bind_data的方法,并在初始化該控件的時候,調(diào)用這個被注解標注過的方法。
<variable
name="data"
type="ObservableArrayList<MultipleListBean>" />
<android.support.v7.widget.RecyclerView
android:id="@+id/main_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind_data="@{data}" />
在activity當中設置這個數(shù)據(jù)源。
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
beans = new ObservableArrayList<>();
beans.add(new MultipleListBean(1, bean));
beans.add(new MultipleListBean(1, bean1));
binding.setData(beans);
以上介紹差不多就是dataBinding的一些基礎內(nèi)容的介紹了。歡迎留言討論。