咱們經過兩篇文章,分別介紹了 DataBinding(Android Jetpack系列——細說DataBinding
) ,以及 DataBinding 的簡單使用(DataBinding 的簡單使用
) ,這篇文章,咱們來介紹一下 DataBinding 最佳實踐——Binding adaptersjava
我之因此說 Binding adapters 是 DataBinding 的最佳實踐,是由於用過了才知道是真的好用!android
下面咱們就經過這篇文章全面的介紹一下 Binding adapters。數組
請耐心看完這篇文章,就知道真的好用!bash
在正式介紹 Binding adapters 以前,咱們先了解一下 DataBinding 裏的註解方法。app
用於數據更新自動刷新視圖。框架
這個註解用於支持自定義屬性,或者是修改原有屬性。註解值能夠是已有的 xml 屬性,例如 android:src、android:text等,也能夠自定義屬性而後在 xml 中使用。ide
列如官方示列當中,就介紹了個 「setPadding」 的例子。佈局
@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, padding: Int) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom())
}
複製代碼
接受多個屬性的適配器。ui
@BindingAdapter(value = { "imageUrl", "error" }, requireAll = false)
fun loadImage(view: ImageView, url: String, error: Drawable) {
Picasso.get().load(url).error(error).into(view)
}
複製代碼
從上面,咱們能夠注意到幾個關鍵的地方:url
這裏須要特殊說明的是:
當發生衝突時,定義的綁定適配器將覆蓋Android框架提供的默認適配器。
DataBinding默承認以在佈局中使用setter方法做爲自定義屬性,
可是若是不是setter格式的方法就要使用BindingMethod註解了. 經過建立一個自定義屬性來關聯一個類中已有的方法。
該註解屬於一個容器. 內部參數是一個@BindingMethod數組, 只能用於修飾類(任意類均可以, 類能夠爲空).
下面咱們看一看官方示例:
@BindingMethods(value = [
BindingMethod(
type = android.widget.ImageView::class,
attribute = "android:tint",
method = "setImageTintList")])
複製代碼
這裏須要注意的是,這個註解必須有三個屬性。
會在指定的字節碼(type)中尋找方法(method), 而後經過你建立的佈局屬性(Attribute)來回調方法。
若是屬性名和@BindingAdapter衝突會報錯
該註解只是單純地關聯已有的方法, 並不能新增方法. 因此全都是註解的空類.
屬性值自動進行類型轉換
列如,咱們用的 android:background 屬性是 Drawable 的,可是須要指定一個顏色值,而這個值是整數的。
那麼我就須要用到了 @BindingConversion 註解。
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
複製代碼
這裏咱們就能夠用帶有bindingConversion註釋的靜態方法進行轉換,以下所示:
@BindingConversion
fun convertColorToDrawable(color: Int) = ColorDrawable(color)
複製代碼
可是,綁定表達式中提供的值類型必須一致。不能在同一表達式中使用不一樣的類型,列如以下的錯誤示範:
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
複製代碼
經過,以上咱們能夠注意到:
經過上面的介紹,咱們瞭解到了這幾個註釋方法,接下來,咱們就要開始使用這些方法。
下面就開始實踐使用:
這個註解的理解仍是十分簡單的。
使用 @Bindable 來標記的 get 方法,在編譯時,會在BR類當中生成對應的字段,而後與 notifyPropertyChanged() 方法配合使用,當該字段中的數據被修改時,dataBinding 會自動刷新對應view的數據,而不用咱們在拿到新數據後從新把數據在setText()一遍,就憑這一點,dataBinding就能夠簡化大量的代碼。
以此來實現雙向綁定,關於雙向綁定的內容,我會經過下一篇文章來詳細講述,如今先簡單介紹一下使用。
,而是實現Observable接口,可是須要自行處理一些接口方法邏輯,BaseObservable是實現Observable接口的類,內部已經作好了相關邏輯處理,因此選擇繼承BaseObservable相對簡單一些。
接下來咱們看一下如何在代碼裏實現:
class StudentInfo : BaseObservable() {
@get:Bindable
var name: String? = null
@get:Bindable
var age: Int = 0
@get:Bindable
var sex: String? = null
@get:Bindable
var score: Int = 0
}
複製代碼
這樣,咱們的實體類就完成了。具體的使用方法和效果,咱們在以後講解雙向綁定的時候會着重介紹。
這裏咱們必須着重介紹一下 BindingAdapter 這個註解。這個多是咱們在以後的使用當中,最經常使用的一個註解。
這個註解厲害了!
除了從新定義已經有的方法,還能夠定義新的屬性!
列如,咱們有個View既沒有android:xxx=""或者app:xxx=""屬性,也沒有setXxx()方法,咱們經過@BindingAdapter一樣能夠實現自定義android:xxx=""或者app:xxx=""屬性,而後使用!
除了定義屬性職位,咱們還能夠定義一些不屬於這個View的屬性!
咱們能夠經過 @BindingAdapter 自定義一個或者一些屬性,讓咱們能夠在這個View當中,使用相應的屬性!
例如咱們定一個ImageView經過 @BindingAdapter 來定義一些屬性。
@BindingAdapter(value = {"android:imageUrl", "android:placeHolder", "android:error"}, requireAll = false)
public static void loadImage(ImageView view, String url, Drawable error, Drawable placeHolder) {
Glide.with(view.getContext()).load(url).into(view);
}
複製代碼
定義好以後,咱們就能夠開始使用了!
<ImageView
android:id="@+id/iv_binding_adapter"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:placeHolder="@{@drawable/ic_launcher"
android:imageUrl="@{url}"
android:error="@{@drawable/ic_launcher}"
/>
複製代碼
還有一點注意的是,咱們設置glide的時候,別忘了在AndroidManifest文件當中把權限設置上!
<uses-permission android:name="android.permission.INTERNET" />
複製代碼
接下來,咱們就能夠看到咱們要實現的效果了
是否是很厲害!這樣,咱們能夠節約多少代碼!
以上只是一個簡單的使用,還有更厲害的!
那就是配合RecyclerView設置adapter。RecyclerView能夠說是咱們最經常使用的一個控件,若是吧adapter和DataBinding結合以後,你會發現寫Adapter會變得十分的簡單!
更多的屬性,均可以在xml當中完成。
咱們能夠爲RecyclerView的Adapter當中,設置咱們經常使用的一些屬性,好比 setOnItemClickListener 、 setOnLoadMoreListener 、
setEnableLoadMore 、setOnRefreshListener等等這些咱們經常使用的一些方法。
列如,咱們能夠定義一個BindAdapter
public class RecyclerViewBindingAdapter {
@BindingAdapter(value = {"android:onItemClick", "android:onLoadMore",
"android:loadMoreEnable"}, requireAll = false)
public static void setupAdapter(RecyclerView recyclerView, final ItemClickListener itemClickListener,
final LoadMoreListener loadMoreListener, final boolean loadMoreEnable) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter == null || !(adapter instanceof BaseQuickAdapter)) {
return;
}
BaseQuickAdapter quickAdapter = (BaseQuickAdapter) adapter;
quickAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
itemClickListener.onItemClick(adapter, view, position);
}
});
quickAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
@Override
public void onLoadMoreRequested() {
loadMoreListener.onLoadMore();
}
}, recyclerView);
quickAdapter.setEnableLoadMore(loadMoreEnable);
quickAdapter.setLoadMoreView(new RVLoadMoreView());
quickAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);
}
public interface ItemClickListener {
void onItemClick(BaseQuickAdapter adapter, View view, int position);
}
public interface LoadMoreListener {
void onLoadMore();
}
}
複製代碼
在佈局文件當中,使用咱們剛纔定義的屬性
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:loadMoreEnable="@{true}"
android:onItemClick="@{presenter.onItemClick}"
android:onLoadMore="@{presenter.onLoadMore}"
app:adapter="@{adapter}"
app:layoutManager="LinearLayoutManager"/>
複製代碼
經過上面的方式,咱們就實現了經過在RecyclerView中配置屬性達到爲adapter設置點擊監聽,上拉加載監聽,以及是否開啓監聽的目的。
這裏值得注意的是:
其中的app:adapter="@{adapter}"是由於RecyclerView有setAdapter方法,結合databinding的特性,故而能夠這樣寫。而app:layoutManager="LinearLayoutManager"屬性是RecyclerView本身提供的一個屬性,爲了方便咱們爲RecyclerView設置layoutManager,其內部採用反射構造一個目標layoutManager,而後經過RecyclerView的public void setLayoutManager(LayoutManager layout)再進行設置。
相信,經過上面的內容。已經能體會到了DataBinding的便捷之處。接下來,咱們在講講雙向綁定。若有任何問題,歡迎給我留言,咱們一塊兒討論。