ButterKnife数据绑定

首先在这里我讲的不会特别深,具体让大家对mvvm模式和databinding进行一个大概的了解;

MVC:

主要分为3层:view(主要为用户界面):

主要为xml文件和一些自定义view;发送指令到业务逻辑层;

 

controller(业务逻辑):

activity,fragment,adapter;根据view层的指令通知model层改变当前状态;

 

model(数据存储)

网路请求、数据解析、;请求数据和发送数据到view,用户得到反馈

 

MVVM(modelview和viewmodel):

Model:数据实现和逻辑处理;

view:界面显示;

viewmodel:将model和view绑定,model的改变通过viewmodel反馈给view;(databinding绑定数据和视图,双向绑定,View的变动,自动反映在viewmodel,反之亦然)

 

 

 

 

 

 

使开发者可以快速构建丰富的具有响应式的用户式体验 ,改善应用程序的开发,使代码更加干净优雅 ;

 

相关文档以及DEMO

https://github.com/LyndonChin/MasteringAndroidDataBinding    databinding入门及高级用法

 

http://www.jianshu.com/p/2d3227d9707d    相关资料

 

https://realm.io/cn/news/data-binding-android-boyar-mount/    棉花糖视频解疑

 

https://github.com/tianzhijiexian/DBinding    DBinging(databinding改造库)

 

https://www.zybuluo.com/shark0017/note/256112   DBinging使用指南

 

http://blog.csdn.net/jdsjlzx/article/details/48133293详细指南

 

http://www.jianshu.com/p/c481d1f4e0b6   双向绑定

 

DEMO导入步骤:

demo:

版本改正dao自己当前编译环境版本:

compileSdkVersion 23
buildToolsVersion "23.0.3"

defaultConfig {
    applicationId "kale.dbinding"
   
 minSdkVersion 15
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"

}

 

//recyclerview包不能填写固定版本

compile 'com.android.support:recyclerview-v7:+'

 

//设置支持databinding

dataBinding {
    enabled = true

}

项目 build.gradle

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

classpath 'me.tatarka:gradle-retrolambda:3.2.0'//lambda

 

simple高版本AS可以使用,AS 2.2 Alpha  gradle  classpath 'com.android.tools.build:gradle:2.2.0-alpha2'

 

 

 

传统代码布局写法:

<LinearLayout …>
    <TextView android:id="@+id/name"/>

    <TextView android:id="@+id/lastName"/>

</LinearLayout>

 

 

private TextView mName;

protected void onCreate(Bundle savedInstanceState) {

  setContentView(R.layout.activity_main);
  mName = (TextView) findViewById(R.id.name);
  mLastName = (TextView) findViewById(R.id.lastName);}public void updateUI(User user) {
  if (user == null) {
    mName.setText(null);
    mLastName.setText(null);
  } else {
    mName.setText(user.getName());
    mLastName.setText(user.getLastName());

  }}

使用一些布局集成框架(ButterKnife):

 

@BindView(R.id.title) TextView title;

  @BindView(R.id.subtitle) TextView subtitle;

  @BindView(R.id.footer) TextView footer;

 

  @Override public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.simple_activity);

    ButterKnife.bind(this);

    // TODO Use fields...

  }

 

使用databinding绑定:

 

private ActivityMainBinding mBinding;

protected void onCreate(Bundle savedInstanceState) {

  mBinding = DataBindingUtil.setContentView(this,

                          R.layout.activity_main);

}


public void updateUI(User user) {

  mBinding.setUser(user);

}

 

布局文件:从我们当前的布局文件中就可以直接看出当前view的绑定数据,当添加新的view的时候,不需要改变其他的java代码;方便在布局查找当前程序的BUG;

<layout>

    <data>

        <!--绑定type的包下的对象,name为当前布局使用-->

        <variable name="user"
                  type="com.android.example.User"/>
    </data>

    <LinearLayout …>

       <TextView android:text="@{user.name}"/>

        <TextView android:text="@{user.lastName}"/>

        <TextView android:text="@{"" + user.age}"/>

</LinearLayout>

</layout>

DataBinding的工作模式:

一、进入处理布局文件:在程序编译期间,将程序的中的布局文件找到获取里边的信息,并且删除视图里无关视图的信息(系统对此视图不能解析和识别);

 

二:通过语法解析表达式:

<TextView android:visibility="@{user.isAdmin ? View.VISIBLE : View.GONE}"/>

databinding将这些数据解析出来

三;编译时解决相关依赖问题,自动生成相关类文件;

题外:有人说:当你在view层进行数据绑定的时候,会减少view的复用,增加视图的数量,看到这里你会发现并不会产生这样的问题,例如我们当前视图绑定的是一个用户的个人界面的数据,我们只需要传入当前用户的对象,并对视图绑定,和我们在java代码层绑定视图是一个效果。

 

未编译时

<layout xmlns:android="http://schemas.android.com/apk/res/android">

<!--数据-->

    <data>

        <variable name="user" type="com.android.example.User"/>

    </data>

<!--视图-->

  <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <TextView android:text="@{user.name}"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>
        <TextView android:text="@{user.lastname}"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>

    </RelativeLayout>

</layout>

编译过程进入(工作模式一):读出数据并且丢掉视图的不认识的内容,并且为视图设置tag;向下兼容,适应旧系统设备

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <TextView android:tag="binding_1"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>
        <TextView android:tag="binding_2"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>

</RelativeLayout>

 

布局表达式与java代码转换:

<TextView android:text="@{myVariable}"/>
textView.setText(myVariable);
<ImageView android:src="@{user.image}"/>

imageView.setSrc(user.image);

 

如何处理设置图片(使用注解的方式添加对应关系,告知databinding如何处理这类view,只需书写一次):

<ImageView android:src="@{user.image}"/>

imageView.setImageResource(user.image);
          @BindingMethod(
              type = android.widget.ImageView.class,
              attribute = "android:src",
              method = "setImageResource")

 

databinding的亮点之处:

1.允许变量数据访问、方法调用、参数传递、比较、通过索引访问数组,甚至还支持三目运算表达式(旧:user==null?0:user.size()

  简便写法: user.size()??0);

 

2.自动检查是否为null,null值并不会报错;

 

3.使用中括号来操作和访问list和map;  list[]可能为一个集合或者数组

 

使用资源内容:

 

表达式:

android:padding="@{isBig ? @dimen/bigPadding : @dimen/smallPadding}"

内联字符串格式:(字符串格式化)

android:text="@{@string/nameFormat(firstName, lastName)}"

内联复数:

android:text="@{@plurals/banana(bananaCount)}"

 

自动属性:

我们为一个布局添加自定义属性时,databinding自动查找此类的set属性方法,继续判断他的参数类型是否匹配布局中的值(对应类型),示例:DrawaerLayout中大量的setter方法

<android.support.v4.widget.DrawerLayout
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:scrimColor="@{@color/scrim}"/>

 

drawerLayout.setScrimColor(
  resources.getColor(R.color.scrim))

 

 

事件处理:(还需了解)

 

<Button android:onClick="clicked" …/>

<Button android:onClick="@{handlers.clicked}" …/>

<Button android:onClick="@{isAdult ? handlers.adultClick : handlers.childClick}" …/>

<Button android:onTextChanged="@{handlers.textChanged}" …/>

 

数据与View联动改变(详细的观测性)

 

Observable Binding

设置可被观测对象(继承BaseObservabkle),我们当前的datbinding是正向绑定(即单向绑定),当数据变化时,view层会同步改变文字,示例:

 

public class Item extends BaseObservable {
    private String price;

 

    @Bindable(会自动产生一个 BR.price  类似R.java)

    public String getPrice() {
        return this.name;
    }

    public void setPrice(String price) {

        this.price = price;

        //数据改变更新通知

        notifyChange();

       
    }}

如何自定义可被观测的类:(还需了解)

 

public class Item implements Observable {
    private PropertyChangeRegistry callbacks = new …
    …
    @Override
    public void addOnPropertyChangedCallback(
            OnPropertyChangedCallback callback) {
        callbacks.add(callback);
    }
    @Override
    public void removeOnPropertyChangedCallback(
            OnPropertyChangedCallback callback) {
        callbacks.remove(callback);

    }}

 

 

双向绑定: 就是"@{}"改成了"@={}"

 

那么,如何开启双向绑定:

项目的build.gradle:

 

classpath 'com.android.tools.build:gradle:2.1.0-alpha3'

moudle的build.gradle中:

 

android {

    dataBinding.enabled = true
}

 

如何自定义双向绑定;

 

性能问题:

1.databinding基本上是0反射;反射会影响较多性能;

 

2.在使用findviewbyid的流程是每次调用,都会从父布局中开始查找,找到当前id的view并返回view,可想而知性能较差;

     databinding :将布局文件中所有view保存,只需遍历布局一次;

 

<TextView android:text="@{user.address.street}"/>

<TextView android:text="@{user.address.city}2/>

 

你有一个 user.address 和另一个 user.address,Data Binding 将会为此生成如下代码:

 

Address address = user.getAddress();

String street = address.getStreet();

String city = address.getCity();

 

 

RecyclerView 和 Data Binding

 

使用 ViewHolders 对于 ListView 是很常见的,在 RecyclerView 中也是强制实施这个模式。如果你看看 Data Binding 生成的代码,你会发现它实际上会产生 ViewHolder。并带有变量属性,它绑定着那些 View。你也可以很容易地在 RecyclerView 里面中使用。我们创建了一个 ViewHolder,有一些基本方法,和一个静态方法,它传递参数给 UserItemBinding(根据用户的布局文件自动生成的)。你需要调用 UserItemBinding 的 inflate。现在你有一个非常简单的 ViewHolder 类,绑定方法类似这样:

 

public class UserViewHolder extends RecyclerView.ViewHolder {

     static UserViewHolder create(LayoutInflater inflater, ViewGroup parent) {

          UserItemBinding binding = UserItemBinding .inflate(inflater, parent, false);

          return new UserViewHolder(binding);

     }

     private UserItemBinding mBinding;

     private UserViewHolder(UserItemBinding binding) {

          super(binding.getRoot());

          mBinding = binding;

     }

     public void bindTo(User user) {

          mBinding.setUser(user);

          mBinding.executePendingBindings();

     }

}

 

其中有一个小细节要小心,就是调用这个executePendingBindings 当你的数据还无效的时候,数据绑定是等到下一个动画帧之前才设置布局。这就让我们不可以一次性批量绑定完所有的数据内容,因为 RecyclerView 的机制并不是这样。当要绑定一个数据的时候,RecyclerView 会调用 BindView,让你去准备测量这个布局。这就是为什么我们叫这个方法为 executePendingBindings,它使数据绑定刷新所有挂起的更改。否则,它将视为另一个布局失效了。

对于 onCreateViewHolder,它只是调用第一个方法,和 onBind 传到 ViewHolder 对象。就是这样,我们没有写 findViewById,没有设置。一切都已经在你的布局文件中封装好了。

 

public UserViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

  return UserViewHolder.create(mLayoutInflater, viewGroup);}

 

public void onBindViewHolder(UserViewHolder userViewHolder, int position) {

  userViewHolder.bindTo(mUserList.get(position));

 

在前面的代码中,我们显示了一个非常简单直接的实现。比如说,用户 对象的名称更改了。绑定系统将关联它,并重新布局在下一个动画帧。下一个动画帧开始,计算出发生了什么变化,和更新 TextView。然后,TextView 说,好吧,我的文字已经变了,我已经重新布局,现在的情况是我不知道我的新尺寸。让我们去告诉 RecyclerView 它的这个孩子有点困难吧,它需要重新布局它本身。当这一切发生的时候,你不会得到任何的动画,因为你在一切都发生了之后才告诉 RecyclerViewRecyclerView 将尝试修复自身。结果:就没有动画了,但这不是我们想要的。

们希望发生的是,当用户的对象是无效的,我们告诉适配器项目已经改变了。反过来,它会告诉 RecyclerView嘿,你的一个孩子要改变,自己做好准备。”RecyclerView 知道了布局和那些子 View 已经改变了,它会指导他们重新绑定。当他们重新绑定,TextView 会说,好吧,我的文字设置好了,我需要布局。”RecyclerView 会说,好了,别担心,我准备好了,让我量量你。结果:很多动画。你会得到所有的动画,因为一切都发生 RecyclerView 控制下。

 

绑定回调和有效载荷

 

public UserViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

  //recyclerviewAdapter中的创建viewholder方法中,添加绑定回调,

  final UserViewHolder holder = UserViewHolder.create(mLayoutInflater, 
      viewGroup);

  holder.getBinding().addOnRebindCallback(new OnRebindCallback() {

    public boolean onPreBind(ViewDataBinding binding) {

     //如果recyclerview不计算布局,返回false,view不需要更新

      return mRecyclerView != null && mRecyclerView.isComputingLayout();
    }

    public void onCanceled(ViewDataBinding binding) {

     //当recyclerview重新计算布局的时候,回调cancled并且告诉recyclerview那一条改变了,让recyclerview去更新它

      if (mRecyclerView == null || mRecyclerView.isComputingLayout()) {
        return;
      }
      int position = holder.getAdapterPosition();
      if (position != RecyclerView.NO_POSITION) {
        notifyItemChanged(position, DATA_INVALIDATION);
      }
    }

  });
  return holder;}

 

 

玩转Android之MVVM开发模式实战,炫酷的DataBinding!

版权声明:本文为博主原创文章,转载请注明出处。若有错误地方,还望批评指正,不胜感激。

C# 很早就有了MVVM的开发模式,Android手机中的MVVM一直到去年GoogleI\O大会上才推出,姗姗来迟。MVVM这中开发模式的优点自不必多说,可以实现视图和逻辑代码的解耦,而且,按照Google的说法,使用了MVVM的开发模式,还可以提高布局文件的解析速度,个人觉得这一点非常重要。我们在安卓开发中经常需要写很多个findViewById,让人心烦,很多人不想写这个于是用了一些注解框架,可是注解框架无论性能多好,效率总是要低于findViewById的,因此,Android中的MVVM也即databinding可以帮助我们彻底解决这个问题。OK,废话不多说,我们来看看具体要怎么在Android开发中使用MVVM

在低版本的AndroidStudio中使用DataBinding稍微有点麻烦,这里不做介绍。我这里以AndroidStuido2.1为例来介绍DataBinding。本文主要包含以下几方面内容:

1.基本使用

2.绑定ImageView

3.绑定ListView

4.点击事件处理

5.数据更新处理

好了,那就开始吧!

1.基本使用

创建好一个Android Project之后,在gradle文件中添加如下几行代码,表示开启databinding:

1. android {  

2.     dataBinding{  

3.         enabled 

android {

    ...

        ...

        ...

    dataBinding{

        enabled true

    }

}

就是这么简单,一个简单的databinding配置之后,就可以开始使用数据绑定了。

要使用数据绑定,我们得首先创建一个实体类,比如User实体类,如下:

1.  * Created by 王松 on 2016/7/31. 

2. publicclass UserEntity {  

3.     private String username;  

4.     private String nickname;  

5.     private

6.     public UserEntity() {  

7.     public getAge() {  

8.         return

9.     public setAge( age) {  

10.         .age = age;  

11.     public String getNickname() {  

12.         return nickname;  

13.     public setNickname(String nickname) {  

14.         .nickname = nickname;  

15.     public String getUsername() {  

16.         return username;  

17.     public setUsername(String username) {  

18.         .username = username;  

19.     public UserEntity( age, String nickname, String username) {  

20.         .age = age;  

21.         .nickname = nickname;  

22.         .username = username;  

/**

 * Created by 王松 on 2016/7/31.

 */

public class UserEntity {

    private String username;

    private String nickname;

    private int age;

 

    public UserEntity() {

    }

 

    public int getAge() {

        return age;

    }

 

    public void setAge(int age) {

        this.age = age;

    }

 

    public String getNickname() {

        return nickname;

    }

 

    public void setNickname(String nickname) {

        this.nickname = nickname;

    }

 

    public String getUsername() {

        return username;

    }

 

    public void setUsername(String username) {

        this.username = username;

    }

 

    public UserEntity(int age, String nickname, String username) {

        this.age = age;

        this.nickname = nickname;

        this.username = username;

    }

}

然后我们来看看布局文件该怎么写,首先布局文件不再是以传统的某一个容器作为根节点,而是使用<layout></layout>作为根节点,在<layout>节点中我们可以通过<data>节点来引入我们要使用的数据源,如下:

1. <?xml version="1.0" encoding="utf-8"?>  

2. <layout  

3.     xmlns:android="http://schemas.android.com/apk/res/android"

4.     <data>  

5.         <variable  

6.             name="user"

7.             type="org.lenve.databinding1.UserEntity"/>  

8.     </data>  

9.     <LinearLayout  

10.         xmlns:tools="http://schemas.android.com/tools"

11.         android:layout_width="match_parent"

12.         android:layout_height="match_parent"

13.         android:orientation="vertical"

14.         tools:context="org.lenve.databinding1.MainActivity"

15.         <TextView  

16.             android:layout_width="wrap_content"

17.             android:layout_height="wrap_content"

18.             android:text="@{user.username}"/>  

19.         <TextView  

20.             android:layout_width="wrap_content"

21.             android:layout_height="wrap_content"

22.             android:text="@{user.nickname}"/>  

23.         <TextView  

24.             android:layout_width="wrap_content"

25.             android:layout_height="wrap_content"

26.             android:text="@{String.valueOf(user.age)}"/>  

27.     </LinearLayout>  

28. </layout>  

<?xml version="1.0" encoding="utf-8"?>

<layout

    xmlns:android="http://schemas.android.com/apk/res/android"

    >

 

    <data>

 

        <variable

            name="user"

            type="org.lenve.databinding1.UserEntity"/>

    </data>

 

    <LinearLayout

        xmlns:tools="http://schemas.android.com/tools"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        tools:context="org.lenve.databinding1.MainActivity">

 

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@{user.username}"/>

 

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@{user.nickname}"/>

 

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@{String.valueOf(user.age)}"/>

    </LinearLayout>

</layout>

data中定义的variable节点,name属性表示变量的名称,type表示这个变量的类型,实例就是我们实体类的位置,当然,这里你也可以换一种写法,如下:

1. <data>  

2.     <import type="org.lenve.databinding1.UserEntity"/>  

3.     <variable  

4.         name="user"

5.         type="UserEntity"/>  

6. </data>  

    <data>

 

        <import type="org.lenve.databinding1.UserEntity"/>

        <variable

            name="user"

            type="UserEntity"/>

    </data>

先使用import节点将UserEntity导入,然后直接使用即可。但是如果这样的话又会有另外一个问题,假如我有两个类都是UserEntity,这两个UserEntity分属于不同的包中,又该如何?看下面:

1. <data>  

2.     <import type="org.lenve.databinding1.UserEntity" alias="Lenve"/>  

3.     <variable  

4.         name="user"

5.         type="Lenve"/>  

6. </data>  

    <data>

 

        <import type="org.lenve.databinding1.UserEntity" alias="Lenve"/>

        <variable

            name="user"

            type="Lenve"/>

    </data>

import节点中还有一个属性叫做alias,这个属性表示我可以给该类取一个别名,我给UserEntity这个实体类取一个别名叫做Lenve,这样我就可以在variable节点中直接写Lenve了。

看完data节点我们再来看看布局文件,TextViewtext属性被我直接设置为了@{user.username},这样,该TextView一会直接将UserEntity实体类的username属性的值显示出来,对于显示ageTextView,我用了String.valueOf来显示,因为大家知道TextView并不能直接显示int型数据,所以需要一个简单的转换,事实上,我们还可以在{}里边进行一些简单的运算,这些我一会再说。

最后,我们来看看Activity中该怎么写,setContentView方法不能够再像以前那样来写了,换成下面的方式:

1. DataBindingUtil.setContentView(, R.layout.activity_main)  

DataBindingUtil.setContentView(this, R.layout.activity_main)

该方法有一个返回值,这个返回值就是系统根据我们的activity_main.xml布局生成的一个ViewModel类,所以完整写法如下:

1. ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(, R.layout.activity_main);  

ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

有了ViewModel,再把数据绑定上去就可以了,如下:

1. @Override

2. protected onCreate(Bundle savedInstanceState) {  

3.     super.onCreate(savedInstanceState);  

4.     ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(, R.layout.activity_main);  

5.     UserEntity user =  UserEntity();  

6.     user.setAge(

7.     user.setUsername("zhangsan"

8.     user.setNickname(

9.     activityMainBinding.setUser(user);  

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        UserEntity user = new UserEntity();

        user.setAge(34);

        user.setUsername("zhangsan");

        user.setNickname("张三");

        activityMainBinding.setUser(user);

    }

运行,显示效果如下:

OK,那我们刚才还说到可以在@{}进行简单的计算,都有哪些计算呢?我们来看看:

1.基本的三目运算

1. <TextView  

2.     android:layout_width="wrap_content"

3.     android:layout_height="wrap_content"

4.     android:text="@{user.username??user.nickname}"/>  

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@{user.username??user.nickname}"/>

两个??表示如果username属性为null则显示nickname属性,否则显示username属性。

2.字符拼接

1. <TextView  

2.     android:layout_width="wrap_content"

3.     android:layout_height="wrap_content"

4.     android:text="@{`username is :`+user.username}"/>  

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@{`username is :`+user.username}"/>

大家注意,这里的字符拼接不是用单引号哦,用的是ESC按键下面那个按键按出来的。目前DataBinding中的字符拼接还不支持中文。

3.根据数据来决定显示样式

1. <TextView  

2.     android:layout_width="wrap_content"

3.     android:layout_height="wrap_content"

4.     android:background="@{user.age < 30 ? 0xFF0000FF:0xFFFF0000}"

5.     android:text="@{String.valueOf(user.age)}"/>  

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:background="@{user.age < 30 ? 0xFF0000FF:0xFFFF0000}"

            android:text="@{String.valueOf(user.age)}"/>

我在这里给TextView设置背景的时候,做了一个简单的判断,如果用户的年龄小于30,背景就显示为蓝色,否则背景就显示为红色,DataBinding里支持小于号但是不支持大于号,索性,大于小于号我都用转义字符来表示。

另外,DataBinding对于基本的四则运算、逻辑与、逻辑或、取反位移等都是支持的,我这里不再举例。

2.绑定ImageView

OK,上文只是一个简单的绑定文本,下面我们来看看怎么样绑定图片,这里我们还得介绍DataBinding的另一项新功能,就是关于DataBinding自定义属性的问题,事实上,在我们使用DataBinding的时候,可以给一个控件自定义一个属性,比如我们下面即将说的这个绑定ImageView的案例。假设我现在想要通过Picasso显示一张网络图片,正常情况下这个显示很简单,可是如果我要通过DataBinding来实现,该怎么做呢?我们可以使用

1. @BindingAdapter

@BindingAdapter

注解来创建一个自定义属性,同时还要有一个配套的注解的方法。当我们在布局文件中使用这个自定义属性的时候,会触发这个被我们注解的方法,这样说大家可能还有一点模糊,我们来看看新的实体类:

1.  * Created by 王松 on 2016/7/31. 

2. publicclass User {  

3.     private String username;  

4.     private String userface;  

5.     public User() {  

6.     public User(String userface, String username) {  

7.         .userface = userface;  

8.         .username = username;  

9.     @BindingAdapter"bind:userface"

10.     publicstatic getInternetImage(ImageView iv, String userface) {  

11.         Picasso.with(iv.getContext()).load(userface).into(iv);  

12.     public String getUserface() {  

13.         return userface;  

14.     public setUserface(String userface) {  

15.         .userface = userface;  

16.     public String getUsername() {  

17.         return username;  

18.     public setUsername(String username) {  

19.         .username = username;  

/**

 * Created by 王松 on 2016/7/31.

 */

public class User {

    private String username;

    private String userface;

 

    public User() {

    }

 

    public User(String userface, String username) {

        this.userface = userface;

        this.username = username;

    }

 

    @BindingAdapter("bind:userface")

    public static void getInternetImage(ImageView iv, String userface) {

        Picasso.with(iv.getContext()).load(userface).into(iv);

    }

 

    public String getUserface() {

        return userface;

    }

 

    public void setUserface(String userface) {

        this.userface = userface;

    }

 

    public String getUsername() {

        return username;

    }

 

    public void setUsername(String username) {

        this.username = username;

    }

}

新类里边只有两个属性,分别是用户名和用户图像,用户图像中存储的实际上是一个网络图片地址,这里除了基本的get/set方法之外还多了一个叫做getInternetImage的网络方法,这个方法有一个注解@BindAdapter("bind:userface"),该注解表示当用户在ImageView中使用自定义属性userface的时候,会触发这个方法,我在这个方法中来为这个ImageView加载一张图片,这里有一点需要注意,就是该方法必须为静态方法。OK,我们再来看看这次的布局文件:

1. <?xml version="1.0" encoding="utf-8"?>  

2. <layout  

3.     xmlns:android="http://schemas.android.com/apk/res/android"

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

5.     <data>  

6.         <variable  

7.             name="user"

8.             type="org.lenve.databinding2.User"/>  

9.     </data>  

10.     <LinearLayout  

11.         xmlns:tools="http://schemas.android.com/tools"

12.         android:layout_width="match_parent"

13.         android:layout_height="match_parent"

14.         android:orientation="vertical"

15.         tools:context="org.lenve.databinding2.MainActivity"

16.         <ImageView  

17.             android:id="@+id/iv"

18.             android:layout_width="wrap_content"

19.             android:layout_height="wrap_content"

20.             app:userface="@{user.userface}"></ImageView>  

21.         <TextView  

22.             android:layout_width="wrap_content"

23.             android:layout_height="wrap_content"

24.             android:text="@{user.username}"/>  

25.     </LinearLayout>  

26. </layout>  

<?xml version="1.0" encoding="utf-8"?>

<layout

    xmlns:android="http://schemas.android.com/apk/res/android"

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

    >

 

    <data>

 

        <variable

            name="user"

            type="org.lenve.databinding2.User"/>

    </data>

 

    <LinearLayout

        xmlns:tools="http://schemas.android.com/tools"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        tools:context="org.lenve.databinding2.MainActivity">

 

        <ImageView

            android:id="@+id/iv"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            app:userface="@{user.userface}"></ImageView>

 

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@{user.username}"/>

    </LinearLayout>

</layout>

大家注意我在ImageView控件中使用userface属性的时候,使用的前缀不是android而是app哦。再来看看Activity中的代码:

1. @Override

2. protected onCreate(Bundle savedInstanceState) {  

3.     super.onCreate(savedInstanceState);  

4.     ActivityMainBinding dataBinding = DataBindingUtil.setContentView(, R.layout.activity_main);  

5.     dataBinding.setUser( User("http://img2.cache.netease.com/auto/2016/7/28/201607282215432cd8a.jpg"

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        ActivityMainBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        dataBinding.setUser(new User("http://img2.cache.netease.com/auto/2016/7/28/201607282215432cd8a.jpg", "张三"));

    }

就是这么简单,加上网络权限就可以运行了,运行效果如下:

3.绑定ListView

好了,看完了简单使用之后,不知道你有没有喜欢上DataBinding,如果还没有,那就再来看看使用DataBinding来给ListView绑定数据吧,这个你一定会喜欢上的。因为使用这中方式来绑定太简单了。

先来看看我们要做的效果吧:

就是一个ListView,左边显示图片,右边显示文本,这样一个效果。OK,那就一步一步来吧,先是主布局:

1. <?xml version="1.0" encoding="utf-8"?>  

2. <RelativeLayout  

3.     xmlns:android="http://schemas.android.com/apk/res/android"

4.     xmlns:tools="http://schemas.android.com/tools"

5.     android:layout_width="match_parent"

6.     android:layout_height="match_parent"

7.     tools:context="org.lenve.databinding3.MainActivity"

8.     <ListView  

9.         android:id="@+id/lv"

10.         android:layout_width="match_parent"

11.         android:layout_height="match_parent"></ListView>  

12. </RelativeLayout>  

<?xml version="1.0" encoding="utf-8"?>

<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="org.lenve.databinding3.MainActivity">

 

    <ListView

        android:id="@+id/lv"

        android:layout_width="match_parent"

        android:layout_height="match_parent"></ListView>

</RelativeLayout>

主布局很简单,就是一个ListView,再来看看ListView的item布局:

1. <?xml version="1.0" encoding="utf-8"?>  

2. <layout  

3.     xmlns:android="http://schemas.android.com/apk/res/android"

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

5.     <data>  

6.         <variable  

7.             name="food"

8.             type="org.lenve.databinding3.Food"/>  

9.     </data>  

10.     <RelativeLayout  

11.         android:layout_width="match_parent"

12.         android:layout_height="96dp"

13.         android:orientation="vertical"

14.         <ImageView  

15.             android:id="@+id/iv"

16.             android:layout_width="96dp"

17.             android:layout_height="96dp"

18.             android:padding="6dp"

19.             app:img="@{food.img}"/>  

20.         <TextView  

21.             android:id="@+id/description"

22.             android:layout_width="match_parent"

23.             android:layout_height="wrap_content"

24.             android:layout_marginLeft="8dp"

25.             android:layout_toRightOf="@id/iv"

26.             android:ellipsize="end"

27.             android:maxLines=

28.             android:text="@{food.description}"/>  

29.         <TextView  

30.             android:layout_width="wrap_content"

31.             android:layout_height="wrap_content"

32.             android:layout_marginLeft="8dp"

33.             android:layout_toRightOf="@id/iv"

34.             android:layout_alignParentBottom="true"

35.             android:layout_marginBottom="2dp"

36.             android:text="@{food.keywords}"

37.             android:textStyle="bold"/>  

38.     </RelativeLayout>  

39. </layout>  

<?xml version="1.0" encoding="utf-8"?>

<layout

    xmlns:android="http://schemas.android.com/apk/res/android"

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

    >

 

    <data>

 

        <variable

            name="food"

            type="org.lenve.databinding3.Food"/>

    </data>

 

    <RelativeLayout

        android:layout_width="match_parent"

        android:layout_height="96dp"

        android:orientation="vertical">

 

        <ImageView

            android:id="@+id/iv"

            android:layout_width="96dp"

            android:layout_height="96dp"

            android:padding="6dp"

            app:img="@{food.img}"/>

 

        <TextView

            android:id="@+id/description"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:layout_marginLeft="8dp"

            android:layout_toRightOf="@id/iv"

            android:ellipsize="end"

            android:maxLines="3"

            android:text="@{food.description}"/>

 

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="8dp"

            android:layout_toRightOf="@id/iv"

            android:layout_alignParentBottom="true"

            android:layout_marginBottom="2dp"

            android:text="@{food.keywords}"

            android:textStyle="bold"/>

    </RelativeLayout>

</layout>

图片加载、文本加载前两节都已经说过了,这里的东西就没有什么难度了,我们再来看看实体类Food:

1.  * Created by 王松 on 2016/7/31. 

2. publicclass Food {  

3.     private String description;  

4.     private String img;  

5.     private String keywords;  

6.     private String summary;  

7.     public Food() {  

8.     public Food(String description, String img, String keywords, String summary) {  

9.         .description = description;  

10.         .img = img;  

11.         .keywords = keywords;  

12.         .summary = summary;  

13.     @BindingAdapter"bind:img"

14.     publicstatic loadInternetImage(ImageView iv, String img) {  

15.         Picasso.with(iv.getContext()).load(img).into(iv);  

16.     public String getDescription() {  

17.         return description;  

18.     public setDescription(String description) {  

19.         .description = description;  

20.     public String getImg() {  

21.         return

22.     public setImg(String img) {  

23.         .img = img;  

24.     public String getKeywords() {  

25.         return keywords;  

26.     public setKeywords(String keywords) {  

27.         .keywords = keywords;  

28.     public String getSummary() {  

29.         return summary;  

30.     public setSummary(String summary) {  

31.         .summary = summary;  

/**

 * Created by 王松 on 2016/7/31.

 */

public class Food {

    private String description;

    private String img;

    private String keywords;

    private String summary;

 

    public Food() {

    }

 

    public Food(String description, String img, String keywords, String summary) {

        this.description = description;

        this.img = img;

        this.keywords = keywords;

        this.summary = summary;

    }

 

    @BindingAdapter("bind:img")

    public static void loadInternetImage(ImageView iv, String img) {

        Picasso.with(iv.getContext()).load(img).into(iv);

    }

 

    public String getDescription() {

        return description;

    }

 

    public void setDescription(String description) {

        this.description = description;

    }

 

    public String getImg() {

        return img;

    }

 

    public void setImg(String img) {

        this.img = img;

    }

 

    public String getKeywords() {

        return keywords;

    }

 

    public void setKeywords(String keywords) {

        this.keywords = keywords;

    }

 

    public String getSummary() {

        return summary;

    }

 

    public void setSummary(String summary) {

        this.summary = summary;

    }

}

这个实体类中有一个加载图片的方法,加载方式我们上文都已经介绍过了,不多说。好了,再来看看我们的终极Adapter类:

1.  * Created by 王松 on 2016/7/31. 

2. publicclass MyBaseAdapter<T> extends BaseAdapter {  

3.     private Context context;  

4.     private LayoutInflater inflater;  

5.     private layoutId;  

6.     private variableId;  

7.     private List<T> list;  

8.     public MyBaseAdapter(Context context,  layoutId, List<T> list,  resId) {  

9.         .context = context;  

10.         .layoutId = layoutId;  

11.         .list = list;  

12.         .variableId = resId;  

13.         inflater = LayoutInflater.from(context);  

14.     @Override

15.     public getCount() {  

16.         return list.size();  

17.     @Override

18.     public Object getItem( position) {  

19.         return list.get(position);  

20.     @Override

21.     public getItemId( position) {  

22.         return position;  

23.     @Override

24.     public View getView( position, View convertView, ViewGroup parent) {  

25.         ViewDataBinding dataBinding;  

26.          (convertView == 

27.             dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false

28.             dataBinding = DataBindingUtil.getBinding(convertView);  

29.         dataBinding.setVariable(variableId, list.get(position));  

30.         return dataBinding.getRoot();  

/**

 * Created by 王松 on 2016/7/31.

 */

public class MyBaseAdapter<T> extends BaseAdapter {

    private Context context;

    private LayoutInflater inflater;

    private int layoutId;

    private int variableId;

    private List<T> list;

 

    public MyBaseAdapter(Context context, int layoutId, List<T> list, int resId) {

        this.context = context;

        this.layoutId = layoutId;

        this.list = list;

        this.variableId = resId;

        inflater = LayoutInflater.from(context);

    }

 

    @Override

 

    public int getCount() {

        return list.size();

    }

 

    @Override

    public Object getItem(int position) {

        return list.get(position);

    }

 

    @Override

    public long getItemId(int position) {

        return position;

    }

 

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        ViewDataBinding dataBinding;

        if (convertView == null) {

            dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);

        }else{

            dataBinding = DataBindingUtil.getBinding(convertView);

        }

        dataBinding.setVariable(variableId, list.get(position));

        return dataBinding.getRoot();

    }

}

这个大概算是Adapter的终极写法了,如果你按这种方式来写Adapter,那么如果没有非常奇葩的需求,你这个App中可能就只有这一个给ListView使用的Adapter了,为什么这么说呢?因为这个Adapter中没有一个变量和我们的ListView沾边,解释一下几个变量吧:layoutId这个表示item布局的资源id,variableId是系统自动生成的,根据我们的实体类,直接从外部传入即可。另外注意布局加载方式为DataBindingUtil类中的inflate方法。OK,最后再来看看Activity:

1. publicclass MainActivity extends AppCompatActivity {  

2.     private Handler mHandler =  Handler(){  

3.         @Override

4.         public handleMessage(Message msg) {  

5.             MyBaseAdapter<Food> adapter =  MyBaseAdapter<>(MainActivity., R.layout.listview_item, foods, org.lenve.databinding3.BR.food);  

6.             lv.setAdapter(adapter);  

7.     private List<Food> foods;  

8.     private ListView lv;  

9.     @Override

10.     protected onCreate(Bundle savedInstanceState) {  

11.         super.onCreate(savedInstanceState);  

12.         setContentView(R.layout.activity_main);  

13.         lv = ((ListView) findViewById(R.id.lv));  

14.         initData();  

15.     private initData() {  

16.         OkHttpClient client =  OkHttpClient.Builder().build();  

17.         Request request =  Request.Builder().url("http://www.tngou.net/api/food/list?id=1").build();  

18.         client.newCall(request).enqueue( Callback() {  

19.             @Override

20.             public onFailure(Call call, IOException e) {  

21.             @Override

22.             public onResponse(Call call, Response response) throws IOException {  

23.                  (response.isSuccessful()) {  

24.                     parseJson(response.body().string());  

25.     private parseJson(String jsonStr) {  

26.         foods =  ArrayList<>();  

27.             JSONObject jo =  JSONObject(jsonStr);  

28.             JSONArray tngou = jo.getJSONArray("tngou"

29.             ; i < tngou.length(); i++) {  

30.                 JSONObject item = tngou.getJSONObject(i);  

31.                 String description = item.getString("description"

32.                 String img = "http://tnfs.tngou.net/image"+item.getString("img"

33.                 String keywords = "【关键词】 "+item.getString("keywords"

34.                 String summary = item.getString("summary"

35.                 foods.add( Food(description, img, keywords, summary));  

36.             mHandler.sendEmptyMessage(

37.         } catch (JSONException e) {  

38.             e.printStackTrace();  

public class MainActivity extends AppCompatActivity {

 

    private Handler mHandler = new Handler(){

        @Override

        public void handleMessage(Message msg) {

            MyBaseAdapter<Food> adapter = new MyBaseAdapter<>(MainActivity.this, R.layout.listview_item, foods, org.lenve.databinding3.BR.food);

            lv.setAdapter(adapter);

        }

    };

    private List<Food> foods;

    private ListView lv;

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        lv = ((ListView) findViewById(R.id.lv));

        initData();

    }

 

    private void initData() {

        OkHttpClient client = new OkHttpClient.Builder().build();

        Request request = new Request.Builder().url("http://www.tngou.net/api/food/list?id=1").build();

        client.newCall(request).enqueue(new Callback() {

            @Override

            public void onFailure(Call call, IOException e) {

 

            }

 

            @Override

            public void onResponse(Call call, Response response) throws IOException {

                if (response.isSuccessful()) {

                    parseJson(response.body().string());

                }

            }

        });

    }

 

    private void parseJson(String jsonStr) {

        foods = new ArrayList<>();

        try {

            JSONObject jo = new JSONObject(jsonStr);

            JSONArray tngou = jo.getJSONArray("tngou");

            for (int i = 0; i < tngou.length(); i++) {

                JSONObject item = tngou.getJSONObject(i);

                String description = item.getString("description");

                String img = "http://tnfs.tngou.net/image"+item.getString("img");

                String keywords = "【关键词】 "+item.getString("keywords");

                String summary = item.getString("summary");

                foods.add(new Food(description, img, keywords, summary));

            }

            mHandler.sendEmptyMessage(0);

        } catch (JSONException e) {

            e.printStackTrace();

        }

    }

}

OkHttp下载数据和Json解析自不用多说,在构造MyAdapter的时候传入的最后一个参数,是BR中的,这个BR和我们项目中的R文件类似,都是系统自动生成的。

至此,我们使用DataBinding的方式来给ListView加载数据就算完成了。so easy~~~

4.点击事件处理

如果你使用DataBinding,我们的点击事件也会有新的处理方式,首先以ListView为例来说说如何绑定点击事件,在listview_item布局文件中每一个item的根节点添加如下代码:

1. <?xml version="1.0" encoding="utf-8"?>  

2. <layout  

3.     xmlns:android="http://schemas.android.com/apk/res/android"

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

5.     <RelativeLayout  

6.         android:layout_width="match_parent"

7.         android:layout_height="96dp"

8.         android:onClick="@{food.onItemClick}"

9.         android:orientation="vertical"

10.         <ImageView  

11.             android:id="@+id/iv"

12.             android:layout_width="96dp"

13.             android:layout_height="96dp"

14.             android:padding="6dp"

15.             app:img="@{food.img}"/>  

16.     </RelativeLayout>  

17. </layout>  

<?xml version="1.0" encoding="utf-8"?>

<layout

    xmlns:android="http://schemas.android.com/apk/res/android"

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

    >

        ....

        ....

    <RelativeLayout

        android:layout_width="match_parent"

        android:layout_height="96dp"

        android:onClick="@{food.onItemClick}"

        android:orientation="vertical">

 

        <ImageView

            android:id="@+id/iv"

            android:layout_width="96dp"

            android:layout_height="96dp"

            android:padding="6dp"

            app:img="@{food.img}"/>

                ....

                ....

                ....

    </RelativeLayout>

</layout>

OK,我给RelativeLayout容器添了onClick属性,属性的值为food.onItemClick,那么这个onItemClick到底是什么呢?其实就是在实体类Food中定义的一个方法,如下:

1. public onItemClick(View view) {  

2.     Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();  

    public void onItemClick(View view) {

        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();

    }

点击item获取当前position的数据,获取方式也是非常简单,直接get方法获取即可,比传统的ListView的点击事件通过position来获取数据方便多了。如果我想为关键字这个TextView添加点击事件也很简单,和上面一样,这里我就不再贴代码了,文末可以下载源码。

5. 数据更新处理

单纯的更新Food对象并不能改变ListViewUI显示效果,那该怎么做呢?Google给我们提供了三种解决方案,分别如下:

1.让实体类继承自BaseObservable

让实体类继承自BaseObservable,然后给需要改变的字段的get方法添加上@Bindable注解,然后给需要改变的字段的set方法加上notifyPropertyChanged(org.lenve.databinding3.BR.description);一句即可,比如我想点击item的时候把description字段的数据全部改为111,我可以修改Food类变为下面的样子:

1. publicclassextends BaseObservable {  

2.     private String description;  

3.     private String img;  

4.     private String keywords;  

5.     private String summary;  

6.     public Food() {  

7.     public Food(String description, String img, String keywords, String summary) {  

8.         .description = description;  

9.         .img = img;  

10.         .keywords = keywords;  

11.         .summary = summary;  

12.     @BindingAdapter"bind:img"

13.     publicstatic loadInternetImage(ImageView iv, String img) {  

14.         Picasso.with(iv.getContext()).load(img).into(iv);  

15.     public onItemClick(View view) {  

16. //        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();

17.         setDescription("111"

18.     public clickKeywords(View view) {  

19.         Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();  

20.     @Bindable

21.     public String getDescription() {  

22.         return description;  

23.     public setDescription(String description) {  

24.         .description = description;  

25.         notifyPropertyChanged(org.lenve.databinding3.BR.description);  

26.     public String getImg() {  

27.         return

28.     public setImg(String img) {  

29.         .img = img;  

30.     public String getKeywords() {  

31.         return keywords;  

32.     public setKeywords(String keywords) {  

33.         .keywords = keywords;  

34.     public String getSummary() {  

35.         return summary;  

36.     public setSummary(String summary) {  

37.         .summary = summary;  

public class Food extends BaseObservable {

    private String description;

    private String img;

    private String keywords;

    private String summary;

 

    public Food() {

    }

 

    public Food(String description, String img, String keywords, String summary) {

        this.description = description;

        this.img = img;

        this.keywords = keywords;

        this.summary = summary;

    }

 

    @BindingAdapter("bind:img")

    public static void loadInternetImage(ImageView iv, String img) {

        Picasso.with(iv.getContext()).load(img).into(iv);

    }

 

    public void onItemClick(View view) {

//        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();

        setDescription("111");

    }

 

    public void clickKeywords(View view) {

        Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();

    }

 

 

    @Bindable

    public String getDescription() {

        return description;

    }

 

    public void setDescription(String description) {

        this.description = description;

        notifyPropertyChanged(org.lenve.databinding3.BR.description);

    }

 

    public String getImg() {

        return img;

    }

 

    public void setImg(String img) {

        this.img = img;

    }

 

    public String getKeywords() {

        return keywords;

    }

 

    public void setKeywords(String keywords) {

        this.keywords = keywords;

    }

 

    public String getSummary() {

        return summary;

    }

 

    public void setSummary(String summary) {

        this.summary = summary;

    }

}

OK,这是第一种解决方案,也是比较简单常用的一种。

2.使用DataBinding提供的ObservableFields来创建实体类

这种方式使用起来略微麻烦,除了继承BaseObservable之外,创建属性的方式也变成下面这种:

1. privatefinal ObservableField<String> description =  ObservableField<>();  

private final ObservableField<String> description = new ObservableField<>();

属性的读写方式也变了,读取方式如下:

1. description.get()  

description.get()

写入方式如下:

1. .description.set(description);  

this.description.set(description);

OK,依据上面几个规则,我新定义的实体类如下:

1.  * Created by 王松 on 2016/7/31. 

2. publicclassextends BaseObservable {  

3.     privatefinal ObservableField<String> description =  ObservableField<>();  

4.     privatefinal ObservableField<String> img =  ObservableField<>();  

5.     privatefinal ObservableField<String> keywords =  ObservableField<>();  

6.     privatefinal ObservableField<String> summary =  ObservableField<>();  

7.     public Food() {  

8.     public Food(String description, String img, String keywords, String summary) {  

9.         .description.set(description);  

10.         .keywords.set(keywords);  

11.         .img.set(img);  

12.         .summary.set(summary);  

13.     @BindingAdapter"bind:img"

14.     publicstatic loadInternetImage(ImageView iv, String img) {  

15.         Picasso.with(iv.getContext()).load(img).into(iv);  

16.     public onItemClick(View view) {  

17. //        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();

18.         setDescription("111"

19.     public clickKeywords(View view) {  

20.         Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();  

21.     @Bindable

22.     public String getDescription() {  

23.         return description.get();  

24.     public setDescription(String description) {  

25.         .description.set(description);  

26.         notifyPropertyChanged(org.lenve.databinding3.BR.description);  

27.     public String getImg() {  

28.         return img.get();  

29.     public setImg(String img) {  

30.         .img.set(img);  

31.     public String getKeywords() {  

32.         return keywords.get();  

33.     public setKeywords(String keywords) {  

34.         .keywords.set(keywords);  

35.     public String getSummary() {  

36.         return summary.get();  

37.     public setSummary(String summary) {  

38.         .summary.set(summary);  

/**

 * Created by 王松 on 2016/7/31.

 */

public class Food extends BaseObservable {

    private final ObservableField<String> description = new ObservableField<>();

    private final ObservableField<String> img = new ObservableField<>();

    private final ObservableField<String> keywords = new ObservableField<>();

    private final ObservableField<String> summary = new ObservableField<>();

    public Food() {

    }

 

    public Food(String description, String img, String keywords, String summary) {

        this.description.set(description);

        this.keywords.set(keywords);

        this.img.set(img);

        this.summary.set(summary);

    }

 

    @BindingAdapter("bind:img")

    public static void loadInternetImage(ImageView iv, String img) {

        Picasso.with(iv.getContext()).load(img).into(iv);

    }

 

    public void onItemClick(View view) {

//        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();

        setDescription("111");

    }

 

    public void clickKeywords(View view) {

        Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();

    }

 

 

    @Bindable

    public String getDescription() {

        return description.get();

    }

 

    public void setDescription(String description) {

        this.description.set(description);

        notifyPropertyChanged(org.lenve.databinding3.BR.description);

    }

 

    public String getImg() {

        return img.get();

    }

 

    public void setImg(String img) {

        this.img.set(img);

    }

 

    public String getKeywords() {

        return keywords.get();

    }

 

    public void setKeywords(String keywords) {

        this.keywords.set(keywords);

    }

 

    public String getSummary() {

        return summary.get();

    }

 

    public void setSummary(String summary) {

        this.summary.set(summary);

    }

}

这种方式实现的功能和第一个实体类实现的功能一模一样。

3.使用DataBinding中提供的集合来存储数据即可

DataBinding中给我们提供了一些现成的集合,用来存储数据,比如ObservableArrayListObservableArrayMap,因为这些用的少,我这里就不做介绍了。

本文共涉及到三个Demo,由于CSDN对上传文件大小的限制,我分三次上传,下载地址如下:

1.http://download.csdn.net/detail/u012702547/9591142

2.http://download.csdn.net/detail/u012702547/9591150

3.http://download.csdn.net/detail/u012702547/9591160

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大伟伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值