咱们经过两篇文章,分别介绍了 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的便捷之处。接下来,咱们在讲讲双向绑定。若有任何问题,欢迎给我留言,咱们一块儿讨论。