继续上篇的博客《Android官方数据绑定框架DataBinding(一)》我们继续学习Data Binding的使用。

十、inflate
不知道大家注意没有,上面的代码我们都是在activity中通过DataBindingUtil.setContentView来加载的布局的,现在有个问题了,如果我们是在Fragment中使用呢?Fragment没有setContentView怎么办?不要着急,Data Binding也提供了inflate的支持!
使用方法如下,大家肯定会觉得非常眼熟。

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);

接下来,我们就尝试着在Fragment中使用一下Data Binding吧。
首先还是那个学生类,Student

public class Student extends BaseObservable {private String name;private int age;public Student() {}public Student(int age, String name) {this.age = age;this.name = name;}@Bindablepublic int getAge() {return age;}public void setAge(int age) {this.age = age;notifyPropertyChanged(org.loader.app5.BR.age);}@Bindablepublic String getName() {return name;}public void setName(String name) {this.name = name;notifyPropertyChanged(org.loader.app5.BR.name);}
}

这里面代码如果看不懂了,请翻看前一篇博客。
继续,activity的布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><FrameLayout
        android:id="@+id/container"android:layout_width="wrap_content"android:layout_height="wrap_content"/></RelativeLayout>

activity的代码,

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getSupportFragmentManager().beginTransaction().replace(R.id.container, new MyFragment()).commit();}
}

重点来了,我们这里data binding的操作都放在了fragment里,那么我们先来看看fragment的布局。

<layout xmlns:android="http://schemas.android.com/apk/res/android"><data class=".Custom"><import type="org.loader.app5.Student" /><variable
            name="stu"type="Student" /><variable
            name="frag"type="org.loader.app5.MyFragment" /></data><LinearLayout
        android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="@{frag.click}"android:text="@{stu.name}"/><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(stu.age)}"/></LinearLayout>
</layout>

如果你看过上篇博客,那么这里也很简单,简单说一下吧。两个TextView分别绑定了Student的name和age字段,而且给name添加了一个点击事件,点击后会调用Fragment的click方法。我们来迫不及待的看一下Fragment怎么写:

public class MyFragment extends Fragment {private Student mStu;@Nullable@Overridepublic View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {org.loader.app5.Custom binding = DataBindingUtil.inflate(inflater,R.layout.frag_layout, container, false);mStu = new Student(20, "loader");binding.setStu(mStu);binding.setFrag(this);return binding.getRoot();}public void click(View view) {mStu.setName("qibin");mStu.setAge(18);}
}

onCreateView中,不同于在Activity中,这里我们使用了DataBindingUtil.inflate方法,接受4个参数,第一个参数是一个LayoutInflater对象,正好,我们这里可以使用onCreateView的第一个参数,第二个参数是我们的布局文件,第三个参数是一个ViewGroup,第四个参数是一个boolean类型的,和在LayoutInflater.inflate一样,后两个参数决定了是否想container中添加我们加载进来的布局。
下面的代码和我们之前写的并无差别,但是有一点,onCreateView方法需要返回一个View对象,我们从哪获取呢?ViewDataBinding有一个方法getRoot可以获取我们加载的布局,是不是很简单?
来看一下效果:

十一、 Data Binding VS RecyclerView
有了上面的思路,大家是不是也会在ListView和RecyclerView中使用了?我们仅以一个RecyclerView来学习一下。
首先来看看item的布局,

<layout xmlns:android="http://schemas.android.com/apk/res/android"><data><variable
            name="stu"type="org.loader.app6.Student" /></data><RelativeLayout
        android:layout_width="match_parent"android:layout_height="match_parent"><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{stu.name}"android:layout_alignParentLeft="true"/><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{String.valueOf(stu.age)}"android:layout_alignParentRight="true"/></RelativeLayout>
</layout>

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

private RecyclerView mRecyclerView;
private ArrayList<Student> mData = new ArrayList<Student>() {{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<MyAdapter.ViewHolder> {private ArrayList<Student> mData = new ArrayList<>();private MyAdapter(ArrayList<Student> data) {mData.addAll(data);}@Overridepublic 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;}@Overridepublic void onBindViewHolder(ViewHolder viewHolder, int i) {viewHolder.getBinding().setVariable(org.loader.app6.BR.stu, mData.get(i));viewHolder.getBinding().executePendingBindings();}@Overridepublic 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对象,并给它提供了GetterSetter方法, 这个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,现在看起来,我们的代码更加简洁了,而且不需要保存控件的实例,是不是很爽? 来看看效果:

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

<layout xmlns:android="http://schemas.android.com/apk/res/android"><data class=".Custom"><variable
            name="str"type="android.databinding.ObservableField&lt;String>" /><variable
            name="handler"type="org.loader.app7.MainActivity" /></data><TextView
        android:id="@+id/textView"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@{str.get}"android:onClick="@{handler.click}"/>
</layout>

xml中代码没有什么好说的,都是之前的代码,如果在这有点迷糊,建议你还是回头看看上篇博客。需要注意的是,
我们给TextView了一个id-textView
activity,

public class MainActivity extends AppCompatActivity {private org.loader.app7.Custom mBinding;private ObservableField<String> mString;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);mString = new ObservableField<String>();mString.set("loader");mBinding.setStr(mString);mBinding.setHandler(this);}public void click(View view) {mString.set("qibin");mBinding.textView.setTextColor(Color.GREEN);}
}

主要还是来看click方法中,这里我们需要获取TextView的实例,用来改变他的颜色,我们是通过ViewDataBinding类的实例直接去获取的。

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

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

<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><data class=".Custom"><variable
            name="imageUrl"type="String" /></data><ImageView
        android:layout_width="match_parent"android:layout_height="wrap_content"app:image="@{imageUrl}"/>
</layout>

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

public class MainActivity extends AppCompatActivity {@Overrideprotected 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了,不信来看。

<ImageView
    android:layout_width="match_parent"android:layout_height="wrap_content"app:image="@{imageUrl}"/>

看看运行结果:

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

<layout xmlns:android="http://schemas.android.com/apk/res/android"><data class=".Custom"><variable
            name="time"type="java.util.Date" /></data><TextView
        android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@{time}"/>
</layout>

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

public class MainActivity extends AppCompatActivity {@Overrideprotected 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 {@BindingConversionpublic 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上就显示出我们转化好的字符串。
看看效果:

好了,到这里DataBinding的知识我们就算学习完了,在学完之后发现这东西也没什么难度,学会使用就ok了,而且android官网也有非常详细的文档,
这两篇博客只是系统的去讲解了DataBinding的使用,大家在以后使用的过程中发现忘记怎么用了,可以再来翻看博客或者直接去官方查看。
ok, 那就到这里吧,下次见。

参考链接:https://developer.android.com/tools/data-binding/guide.html

博客源码下载:代码下载,戳这里

Android官方数据绑定框架DataBinding(二)相关推荐

  1. Android官方数据绑定框架DataBinding(一)

    还记得在博客<高逼格UI-ASD(Android Support Design)>的开始曾经说过,Android最新推出了一个官方的数据绑定框架-Data Binding Library. ...

  2. Android数据绑定框架DataBinding用法

    Android数据绑定框架DataBinding用法     [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/5195374 ...

  3. Android开发之关于MVVM架构中视图数据绑定框架dataBinding的基本用法

    dataBinding是Google官方开发的第三方视图数据绑定框架.优缺点如下: 优点:很好用 缺点:调试bug不易,部分AS版本中不太友好 首先说下如何使用: 在gradle中的android模块 ...

  4. android 最新框架组合,android 官方mvp框架优化:lifecycle-mvp,像前端那样组合式写页面...

    目录 1 前言 虽然在标题上,自己很随意的起了这么一个名字.其实并不是说它起个英文名就牛逼了.说白了,它其实就是mvp的思想加了lifecycle-component,然后加入了分层的思想,最后用Ty ...

  5. 第五章 网络 之 Android网络知识框架(二)

    文章目录 一.Android实现网络请求的主流方法 1.1 HttpClient (1)简介 (2)实现 1.2 HttpURLConnection (1)简介 (2)实现 1.3 对比 二.主流网络 ...

  6. NoHttp使用简析——Android网络请求框架(二)

    题记-- 静坐窗前,与明月为伴. 每一天都是一个新的开始,每一天都是一个新的心态,每一天的目标都是品好每一杯白开水. 生活的价值是活的有意义,而活的有意义就是生命的折腾. 在功夫的世界中,唯快不破,在 ...

  7. 基于Android官方AsyncListUtil优化经典ListView分页加载机制(二)

    基于Android官方AsyncListUtil优化经典ListView分页加载机制(二) 我写的附录文章1,介绍了如何使用Android官方的分页加载框架AsyncListUtil优化改进常见的Re ...

  8. Android流行框架(二)

    第一部分 个性化控件(View) 主要介绍那些不错个性化的 View,包括 ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.P ...

  9. Android Http请求框架二:xUtils 框架网络请求

    一:对Http不了解的请看 Android Http请求框架一:Get 和 Post 请求 二.正文 1.xUtils 下载地址 github 下载地址  : https://github.com/w ...

最新文章

  1. 数据缺失、混乱、重复怎么办?最全数据清洗指南!
  2. 如何取消或定制当点击GridView 的时候出现的那个黄色背景
  3. (UVA)1586 --Molar Mass(分子量)
  4. 从(0,0)到(n,n)——广度优先及其改进
  5. 概念区分:并行、分布式、集群、云、超算
  6. [html] marquee详解
  7. 极简的 PNG 编码函数 svpng(),用来学习C语言,真的很爽
  8. 从1.5k到18k, 一个程序员的5年成长之路 2019-03-15
  9. 使用Python字符串的编码与解码方法实现信息加解密
  10. 移除inline-block间隙
  11. 表单提交复选框(checkbox)注意事项
  12. python类型转换方法_Numpy数据类型转换astype,dtype的方法
  13. 【前端工程化】使用tippy.js代替自定义的popover/tooltip
  14. VS2013漂亮字体
  15. JAVA实现Doc与Docx互转
  16. QGIS下载各种DEM的插件(SRTM 90m/30m -ALOS 30m -Cop 30m/90m-NASADEM Global DEM)
  17. Daily record-October
  18. 单曲循环:一人一wifi
  19. 数字图像处理——形态学操作(二值图像篇)
  20. 前端程序员常用的9大构建工具

热门文章

  1. 英语一和英语二的区别,考研的你知晓了吗?
  2. Android开发工程师vs运维工程师
  3. 面试题 | 帽子问题
  4. Moco -Momentum Contrast for Unsupervised Visual Representation Learning
  5. STMCube学习记录(一)RCC时钟源配置
  6. 5.7.2 使用设计视图创建交叉表查询
  7. 程序员的浪漫——欲寄彩笺兼尺素,山长水阔知何处
  8. 求1~n整数中1出现的次数
  9. 推荐系统遇上深度学习(一三七)-[阿里]广告精排和创意优选联合优化
  10. Win10出现身份验证错误,要求的函数不受支持 可能是由于CredSSP加密Oracle修正。