内容简介:看了谷歌官方文章确实写的太简略了,甚至看完之后有很多地方还不知道怎么回事儿或者怎么用,那么接下来我将通过几篇文章全面介绍一下 DataBinding 以及 DataBinding 的使用。我们通过两篇文章,分别介绍了 DataBinding() ,以及 DataBinding 的简单使用(
看了谷歌官方文章确实写的太简略了,甚至看完之后有很多地方还不知道怎么回事儿或者怎么用,那么接下来我将通过几篇文章全面介绍一下 DataBinding 以及 DataBinding 的使用。
GitHub传送门 欢迎Star 下载
如有任何问题 关注 “朝阳杨少爷” 公众号给我留言,我会及时回复。
写在前面
我们通过两篇文章,分别介绍了 DataBinding( Android Jetpack系列——细说DataBinding
) ,以及 DataBinding 的简单使用( DataBinding 的简单使用
) ,这篇文章,我们来介绍一下 DataBinding 最佳实践——Binding adapters
我之所以说 Binding adapters 是 DataBinding 的最佳实践,是因为用过了才知道是真的好用!
下面我们就通过这篇文章全面的介绍一下 Binding adapters。
请耐心看完这篇文章,就知道真的好用!
DataBinding里的注解方法讲解
在正式介绍 Binding adapters 之前,我们先了解一下 DataBinding 里的注解方法。
@Bindable
用于数据更新自动刷新视图。
@BindingAdapter
这个注解用于支持自定义属性,或者是修改原有属性。注解值可以是已有的 xml 属性,例如 android:src、android:text等,也可以自定义属性然后在 xml 中使用。
列如官方示列当中,就介绍了个 「setPadding」 的例子。
@BindingAdapter("android:paddingLeft") fun setPaddingLeft(view: View, padding: Int) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()) } 复制代码
接受多个属性的适配器。
@BindingAdapter(value = { "imageUrl", "error" }, requireAll = false) fun loadImage(view: ImageView, url: String, error: Drawable) { Picasso.get().load(url).error(error).into(view) } 复制代码
从上面,我们可以注意到几个关键的地方:
- 修饰的方法,必须是 public static
- 方法参数第一个要求必须是 View
- 方法名可以随意
- 最后一个 booblean 类型是可选参数。可以要求是否所有参数都需要填写,默认是true。
- 如果这里requireAll为false, 你没有填写的属性值将为null. 所以需要做非空判断。
这里需要特殊说明的是:
当发生冲突时,定义的绑定适配器将覆盖Android框架提供的默认适配器。
@BindingMethods
DataBinding默认可以在布局中使用setter方法作为自定义属性,
但是如果不是setter格式的方法就要使用BindingMethod注解了. 通过创建一个自定义属性来关联一个类中已有的方法。
该注解属于一个容器. 内部参数是一个@BindingMethod数组, 只能用于修饰类(任意类都可以, 类可以为空).
下面我们看一看官方示例:
@BindingMethods(value = [ BindingMethod( type = android.widget.ImageView::class, attribute = "android:tint", method = "setImageTintList")]) 复制代码
这里需要注意的是,这个注解必须有三个属性。
- type:字节码
- attribute:属性
- method:方法
会在指定的字节码(type)中寻找方法(method), 然后通过你创建的布局属性(Attribute)来回调方法。
如果属性名和@BindingAdapter冲突会报错
该注解只是单纯地关联已有的方法, 并不能新增方法. 所以全都是注解的空类.
@BindingConversion
属性值自动进行类型转换
列如,我们用的 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"/> 复制代码
通过,以上我们可以注意到:
- 只能修饰 public static 方法。
- 任意位置任意方法名都不被限制。
- DataBinding自动匹配被该注解修饰的方法和匹配参数类型。
- 返回值类型必须喝属性setter方法匹配,且参数只能有一个。
- 要求属性值必须是@{}DataBinding表达式。
Binding adapters的使用实践
通过上面的介绍,我们了解到了这几个注释方法,接下来,我们就要开始使用这些方法。
下面就开始实践使用:
@Bindable
这个注解的理解还是十分简单的。
使用 @Bindable 来标记的 get 方法,在编译时,会在BR类当中生成对应的字段,然后与 notifyPropertyChanged() 方法配合使用,当该字段中的数据被修改时,dataBinding 会自动刷新对应view的数据,而不用我们在拿到新数据后重新把数据在setText()一遍,就凭这一点,dataBinding就可以简化大量的代码。
以此来实现双向绑定,关于双向绑定的内容,我会通过下一篇文章来详细讲述,现在先简单介绍一下使用。
实体类也可以不用继承BaseObservable
,而是实现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
这里我们必须着重介绍一下 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}" /> 复制代码
值得注意的是,这里的 @drawable/ic_launcher,用@{}括住资源使其成为有效的绑定表达式。
但是,我有一点疑惑的是,现在我们图片的资源都放在mipmap系列文件夹下了,但是这里设置只能在drawable文件夹下面找到对应的资源?如果有什么想法和办法欢迎给我留言,我们交流一下!
还有一点注意的是,我们设置glide的时候,别忘了在AndroidManifest文件当中把权限设置上!
<uses-permission android:name="android.permission.INTERNET" /> 复制代码
接下来,我们就可以看到我们要实现的效果了
是不是很厉害!这样,我们可以节约多少代码!
以上只是一个简单的使用,还有更厉害的!
那就是配合RecyclerView设置adapter。RecyclerView可以说是我们最常用的一个控件,如果吧adapter和DataBinding结合之后,你会发现写Adapter会变得十分的简单!
更多的属性,都可以在xml当中完成。
setOnItemClickListener 、 setOnLoadMoreListener 、
等等这些我们常用的一些方法。列如,我们可以定义一个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的便捷之处。接下来,我们在讲讲双向绑定。如有任何问题,欢迎给我留言,我们一起讨论。
GitHub传送门 欢迎Star 下载
如有任何问题 关注 “朝阳杨少爷” 公众号给我留言,我会及时回复。
扫一扫,即刻加入到专属限免的星球当中,这里有很多有意思的人,好玩儿的事儿等你来耍!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- vue项目实践004~~~一篮子的实践技巧
- HBase实践 | 阿里云HBase数据安全实践
- Spark 实践:物化视图在 SparkSQL 中的实践
- Spark实践|物化视图在 SparkSQL 中的实践
- HBase实践 | 数据人看Feed流-架构实践
- Kafka从上手到实践-实践真知:搭建Zookeeper集群
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。