DataBingding
博客创建时间:2021.04.12
博客更新时间:2021.04.13
以Android studio build=4.1.3,gradle=6.5,SdkVersion 30来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已
在上一篇博文《Android开发提升效率之DataBinding——基本使用》中,已经对DataBinding有了基本的掌握和使用能力,本篇博文主要对另一些进阶开发做详细的描述和讲解。
public class ListSubjectAdapter extends RecyclerView.Adapter<ListSubjectAdapter.ViewHolder> {
private List<TableSubject> list;
MyOnItemClickListener myOnItemClickListener;
public void setMyOnItemClickListener(@NonNull MyOnItemClickListener myOnItemClickListener) {
this.myOnItemClickListener = myOnItemClickListener;
}
public ListSubjectAdapter() {
}
public void setDatas(@NonNull List<TableSubject> data) {
this.list = data;
notifyDataSetChanged();
}
@NonNull
public TableSubject getItem(int position) {
return list.get(position);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, int viewType) {
ItemListSubjectBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_list_subject, parent, false);
return new ViewHolder(binding);
}
public void removeList(int position) {
if (list != null) {
//删除数据源,移除集合中当前下标的数据
list.remove(position);
//刷新被删除的地方
notifyItemRemoved(position);
//刷新被删除数据,以及其后面的数据
notifyItemRangeChanged(position, getItemCount());
}
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, @SuppressLint("RecyclerView") final int position) {
holder.getBinding().setBean(list.get(position));
holder.getBinding().getRoot().setOnClickListener(v -> {
if (myOnItemClickListener != null) {
myOnItemClickListener.myOnItemClick(position, list.get(position).getSubjectId());
}
});
holder.getBinding().getRoot().setOnLongClickListener(v -> {
return false;
});
holder.binding.executePendingBindings();
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
private void removeItemByPosition(int position) {
list.remove(position);
notifyDataSetChanged();
}
public long getId() {
return getItem(currentPosition).getSubjectId();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final ItemListSubjectBinding binding;
ViewHolder(ItemListSubjectBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
ItemListSubjectBinding getBinding() {
return binding;
}
}
}
RecyclerView中的闪烁问题
@Override
public void onBindViewHolder(@NonNull UserAdapterHolder holder, int position) {
holder.getBinding().setClassName(beans.get(position));
holder.getBinding().setAdapter(this);
holder.getBinding().setPosition(position);
holder.binding.executePendingBindings();
}
holder.binding.executePendingBindings()这个不加上可能会控件显示异常现象。
对于图片的加载,我们可以使用BindingAdapter注解来解决,这样就不用每次都进行ImageView的图片设置操作
public class ImageHelper {
/**
* 1.加载图片,无需手动调用此方法
* 2.使用@BindingAdapter注解设置自定义属性的名称,imageUrl就是属性的名称,
* 当ImageView中使用imageUrl属性时,会自动调用loadImage方法,
*
* @param imageView ImageView
* @param url 图片地址
*/
@BindingAdapter({"imageUrl"})
public static void loadImage(ImageView imageView, String url) {
Glide.with(imageView.getContext()).load(url)
.placeholder(R.mipmap.fruit)
.error(R.mipmap.fruit)
.into(imageView);
}
}
loadImage()一定需要是static修饰
ImageView中配置imageUrl。当图片未加载出来时会有一张图片,如果加载错误则会有另一张图片。
// 具体的使用形式
<!-- 当imageUrl属性存在时,会自动调用ImageHelper的loadImage方法,
参数imageView为当前使用imageUrl属性的ImageView,参数url为图片地址 -->
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:scaleType="centerCrop"
app:imageUrl="@{user.picUrl}" />
1. include中的数据传递
如果在Activity的xml布局使用了include标签,此时想将Activity xml中设置的如click传递给layout,可以进行如下操作。
<data>
<variable name="user" type="com.example.User"/>
</data>
<include
layout="@layout/contact"
app:user="@{user}"/>
// 可以是app:user或者bind:user,其实都一样的可以
2. Data binding不支持直接包含merge 节点
//举个例子, 以下的代码不能正常运行 :
<merge>
<include layout="@layout/contact"
app:user="@{user}"/>
</merge>
3. 事件处理使用方式
方式一:
android:onClick="@{clickListener}"
方式二:
//使用该种方法时末尾是没有 "()"的,要特别注意
android:onClick="@{handler::onClickFriend}"/>
<!-- 注意:函数名和监听器对象必须对应 -->
<!-- 函数调用也可以使用 `.` , 如handler.onClickFriend , 不过已弃用 -->
方式三
android:onCheckedChanged="@{(view,cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
或
android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />
方式二相对于方式一,它的优势在于表达式会在编译时处理,如果方法不存在或者方法签名不对,编译将会报错。
DataDinding中和Java一样支持多种运算符
1. 常规三目运算
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
2.还有如下 格式 ??符号相当于三目运算的简写
android:text="@{user.displayName ?? user.lastName}"
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
3.静态方法的使用
<TextView android:text="@{MyStringUtils.capitalize(user.firstName)}" />
4. 固定内容和变量表达式
android:text='@{"iname:" +user.name}'
有时会报错,此时使用如下样式进行解决
android:text='@{@String/iname +user.name}'
支持的运算符 | 支持的运算符 | 支持的运算符 |
---|---|---|
数学计算 + - / * % | 字符串连接 + | 逻辑 && “11” |
二进制 & 和^ | 一元 + - ! ~ | 位移 >> >>> << |
比较 == > < >= <= | instanceof | 组 () |
字面量 - 字符,字符串,数字, null | 类型转换 | 函数调用 |
字段存取 | 数组存取 [] | 三元运算符 ?: |
不支持的运算符 | 不支持的运算符 | 不支持的运算符 |
---|---|---|
this | super | new |
显式泛型调用 |
在xml布局文件中使用<、>、&、%等符号时会出现错误,此时我们需要将这些特殊符号进行转义,才能正常使用。
如
<data>
<!-- 这种方式是错误的-->
<variable
name="list"
type="java.util.List" />
<!--此方式正确-->
<variable
name="list"
type="java.util.List<String>" />
</data>
显示结果 | 描述 | 转义字符 | 十进制 |
---|---|---|---|
空格 |  ; | ; | |
< | 小于号 | <; | <; |
> | 大于号 | >; | >; |
& | 与号 | &; | &; |
" | 引号 | "; | "; |
‘ | 撇号 | &apos; | '; |
* | 乘号 | ×; | ×; |
% | 除号 | ÷; | ÷; |
本篇博客主要对DataBinding框架的使用中,一些进阶知识点进行总结和归纳。
本测试Demo源码
https://gitee.com/luofaxin/DataBindingAnalysis.git
https://github.com/l424533553/DataBindingAnalysis.git
相关链接:
扩展链接:
扩展训练:
博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !