android注解绑定数据类型,Android官方数据绑定框架DataBinding(三)

十一、 Data Binding VS RecyclerView

有了上面的思路,大家是不是也会在ListView和RecyclerView中使用了?我们仅以一个RecyclerView来学习一下。

首先来看看item的布局,

name="stu"

type="org.loader.app6.Student" />

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@{stu.name}"

android:layout_alignParentLeft="true"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@{String.valueOf(stu.age)}"

android:layout_alignParentRight="true"/>

可以看到,还是用了那个Student实体,这样得代码,相信你也已经看烦了吧。

那我们来看看activity的。

private RecyclerView mRecyclerView;

private ArrayList mData = new ArrayList() {

{

for (int i=0;i<10;i++) add(new Student("loader" + i, 18 + i));

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mRecyclerView = (RecyclerView) findViewById(R.id.recycler);

mRecyclerView.setLayoutManager(new LinearLayoutManager(this,

LinearLayoutManager.VERTICAL, false));

mRecyclerView.setAdapter(new MyAdapter(mData));

}

这里给RecyclerView设置了一个Adapter,相信最主要的代码就在这个Adapter里。

private class MyAdapter extends RecyclerView.Adapter {

private ArrayList mData = new ArrayList<>();

private MyAdapter(ArrayList data) {

mData.addAll(data);

}

@Override

public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater

.from(viewGroup.getContext()), R.layout.item, viewGroup, false);

ViewHolder holder = new ViewHolder(binding.getRoot());

holder.setBinding(binding);

return holder;

}

@Override

public void onBindViewHolder(ViewHolder viewHolder, int i) {

viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i));

viewHolder.getBinding().executePendingBindings();

}

@Override

public int getItemCount() {

return mData.size();

}

class ViewHolder extends RecyclerView.ViewHolder {

private ViewDataBinding binding;

public ViewHolder(View itemView) {

super(itemView);

}

public void setBinding(ViewDataBinding binding) {

this.binding = binding;

}

public ViewDataBinding getBinding() {

return this.binding;

}

}

果然,这个adapter的写法和我们之前的写法不太一样,首先看看ViewHolder,在这个holder里,我们保存了一个ViewDataBinding对象,并给它提供了Getter和Setter方法, 这个ViewDataBinding是干嘛的?我们稍后去讲。继续看看onCreateViewHolder,在这里面,我们首先调用DataBindingUtil.inflate方法返回了一个ViewDataBinding的对象,这个ViewDataBinding是个啥?我们以前没见过啊,这里告诉大家我们之前返回的那些都是ViewDataBinding的子类!继续看代码,我们new了一个holder,参数是肯定是我们的item布局了,继续看,接着我们又把binding设置给了holder,最后返回holder。这时候,我们的holder里就保存了刚刚返回的ViewDataBinding对象,干嘛用呢?继续看onBindViewHolder就知道了。

@Override

public void onBindViewHolder(ViewHolder viewHolder, int i) {

viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i));

viewHolder.getBinding().executePendingBindings();

}

只有两行代码,但是都是我们没有见过的,首先第一行,我们以前都是使用类似binding.setStu这样方法去设置变量,那这个setVariable呢? 为什么没有setStu,这里要记住,ViewDataBinding是我们之前用的那些binding的父类,只有自动生成的那些子类才会有setXXX方法,那现在我们需要在ViewDataBinding中设置变量咋办?这个类为我们提供了setVariable去设置变量,第一个参数是我们的变量名的引用,第二个是我们要设置的值。第二行代码,executePendingBindings的作用是干嘛的?官方的回答是:

当数据改变时,binding会在下一帧去改变数据,如果我们需要立即改变,就去调用executePendingBindings方法。

所以这里的作用就是去让数据的改变立即执行。

ok,现在看起来,我们的代码更加简洁了,而且不需要保存控件的实例,是不是很爽? 来看看效果:

android注解绑定数据类型,Android官方数据绑定框架DataBinding(三)_第1张图片

十二、 View with ID

在使用Data Binding的过程中,我们发现并没有保存View的实例,但是现在我们有需求需要这个View的实例咋办?难道走老路findViewById?当然不是啦,当我们需要某个view的实例时,我们只要给该view一个id,然后Data Binding框架就会给我们自动生成该view的实例,放哪了?当然是ViewDataBinding里面。

上代码:

name="str"

type="android.databinding.ObservableField" />

name="handler"

type="org.loader.app7.MainActivity" />

android:id="@+id/textView"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@{str.get}"

android:onClick="@{handler.click}"/>

xml中代码没有什么好说的,都是之前的代码,如果在这有点迷糊,建议你还是回头看看上篇博客。需要注意的是,

我们给TextView了一个id-textView。

activity,

public class MainActivity extends AppCompatActivity {

private org.loader.app7.Custom mBinding;

private ObservableField mString;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mBinding = DataBindingUtil.setContentView(this,

R.layout.activity_main);

mString = new ObservableField();

mString.set("loader");

mBinding.setStr(mString);

mBinding.setHandler(this);

}

public void click(View view) {

mString.set("qibin");

mBinding.textView.setTextColor(Color.GREEN);

}

}

通过ViewDataBinding类的实例直接去获取的。

只要我们给了view一个id,那么框架就会在ViewDataBinding中自动帮我们保存这个view的实例,变量名就是我们设置的id。

十三、 自定义setter

想想这样的一种情景,一个ImageView需要通过网络去加载图片,那我们怎么办?看似好像使用DataBinding不行,恩,我们上面所学到东西确实不能够解决这个问题,但是DataBinding框架给我们提供了很好的扩展,允许我们自定义setter,那该怎么做呢?这里就要引出另一个知识点——BindingAdapter,这是一个注解,参数是一个数组,数组中存放的是我们自定义的’属性’。接下来就以一个例子学习一下BindingAdapter的使用。

xmlns:app="http://schemas.android.com/apk/res-auto">

name="imageUrl"

type="String" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:image="@{imageUrl}"/>

这里我们增加了一个命名空间app,并且注意ImageView的app:image属性,这里和我们自定义view时自定义的属性一样,但是这里并不需要我们去重写ImageView,这条属性的值是我们上面定义的String类型的imageUrl,从名称中看到这里我们可能会塞给他一个url。

activity,

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

org.loader.app8.Custom binding = DataBindingUtil.setContentView(this,

R.layout.activity_main);

binding.setImageUrl("http://images.csdn.net/20150810/Blog-Image%E5%89%AF%E6%9C%AC.jpg");

}

}

果然在这里我们set了一个url,那图片怎么加载呢?这里就要使用到我们刚才说的BindingAdapter注解了。

public class Utils {

@BindingAdapter({"bind:image"})

public static void imageLoader(ImageView imageView, String url) {

ImageLoaderUtils.getInstance().displayImage(url, imageView);

}

}

我们定义了一个Utils类,这个类你可以随便起名,该类中只有一个静态的方法imageLoader,该方法有两个参数,一个是需要设置数据的view,

一个是我们需要的url。值得注意的是那个BindingAdapter注解,看看他的参数,是一个数组,内容只有一个bind:image,仅仅几行代码,我们不需要

手工调用Utils.imageLoader,也不需要知道imageLoader方法定义到哪了,一个网络图片加载就搞定了,是不是很神奇,这里面起关键作用的就是BindingAdapter

注解了,来看看它的参数怎么定义的吧,难道是乱写?当然不是,这里要遵循一定的规则,

以bind:开头,接着书写你在控件中使用的自定义属性名称。

这里就是image了,不信来看。

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:image="@{imageUrl}"/>

看看运行结果:

android注解绑定数据类型,Android官方数据绑定框架DataBinding(三)_第2张图片

十四、 Converters

Converter是什么呢?举个例子吧:假如你的控件需要一个格式化好的时间,但是你只有一个Date类型额变量咋办?肯定有人会说这个简单,转化完成后在设置,恩,这也是一种办法,但是DataBinding还给我们提供了另外一种方式,虽然原理一样,但是这种方式使用的场景更多,那就是——Converter。和上面的BindingAdapter使用方法一样,这也是一个注解。下面还是以一段代码的形式进行学习。

name="time"

type="java.util.Date" />

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@{time}"/>

看TextView的text属性,我们需要一个String类型的值,但是这里确给了一个Date类型的,这就需要我们去定义Converter去转换它,

activity,

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

org.loader.app9.Custom binding = DataBindingUtil.setContentView(this,

R.layout.activity_main);

binding.setTime(new Date());

}

}

去给这个Date类型的变量设置值。怎么去定义Converter呢? 看代码:

public class Utils {

@BindingConversion

public static String convertDate(Date date) {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

return sdf.format(date);

}

}

和上面一样,我们不需要关心这个convertDate在哪个类中,重要的是他的@BindingConversion注解,这个方法接受一个Date类型的变量,正好我们的android:text设置的就是一个Date类型的值,在方法内部我们将这个Date类型的变量转换成String类型的日期并且返回。这样UI上就显示出我们转化好的字符串。

看看效果:

android注解绑定数据类型,Android官方数据绑定框架DataBinding(三)_第3张图片

好了,到这里DataBinding的知识我们就算学习完了,在学完之后发现这东西也没什么难度,学会使用就ok了,而且android官网也有非常详细的文档

你可能感兴趣的:(android注解绑定数据类型)