转载:


C# 很早就有了MVVM的开发模式,Android手机中的MVVM一直到去年Google的I\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:


[java]  view plain  copy


1. android {  
2.     ...  
3.     ...  
4.     ...  
5.     dataBinding{  
6. true  
7.     }  
8. }


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

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


[java]  view plain  copy



1. /**
2.  * Created by 王松 on 2016/7/31.
3.  */  
4. public class UserEntity {  
5. private String username;  
6. private String nickname;  
7. private int age;  
8.   
9. public UserEntity() {  
10.     }  
11.   
12. public int getAge() {  
13. return age;  
14.     }  
15.   
16. public void setAge(int age) {  
17. this.age = age;  
18.     }  
19.   
20. public String getNickname() {  
21. return nickname;  
22.     }  
23.   
24. public void setNickname(String nickname) {  
25. this.nickname = nickname;  
26.     }  
27.   
28. public String getUsername() {  
29. return username;  
30.     }  
31.   
32. public void setUsername(String username) {  
33. this.username = username;  
34.     }  
35.   
36. public UserEntity(int age, String nickname, String username) {  
37. this.age = age;  
38. this.nickname = nickname;  
39. this.username = username;  
40.     }  
41. }



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


[java]  view plain  copy


1. <?xml version="1.0" encoding="utf-8"?>  
2. <layout  
3. "http://schemas.android.com/apk/res/android"  
4.     >  
5.   
6.     <data>  
7.   
8.         <variable  
9. "user"  
10. "org.lenve.databinding1.UserEntity"/>  
11.     </data>  
12.   
13.     <LinearLayout  
14. "http://schemas.android.com/tools"  
15. "match_parent"  
16. "match_parent"  
17. "vertical"  
18. "org.lenve.databinding1.MainActivity">  
19.   
20.         <TextView  
21. "wrap_content"  
22. "wrap_content"  
23. "@{user.username}"/>  
24.   
25.         <TextView  
26. "wrap_content"  
27. "wrap_content"  
28. "@{user.nickname}"/>  
29.   
30.         <TextView  
31. "wrap_content"  
32. "wrap_content"  
33. "@{String.valueOf(user.age)}"/>  
34.     </LinearLayout>  
35. </layout>


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


[java]  view plain  copy



1. <data>  
2.   
3. import type="org.lenve.databinding1.UserEntity"/>  
4.     <variable  
5. "user"  
6. "UserEntity"/>  
7. </data>



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


[java]  view plain  copy


1. <data>  
2.   
3. import type="org.lenve.databinding1.UserEntity" alias="Lenve"/>  
4.     <variable  
5. "user"  
6. "Lenve"/>  
7. </data>



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

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

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


[java]  view plain  copy



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



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


    [java]  view plain  copy


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


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


    [java]  view plain  copy



      1. @Override  
      2. protected void onCreate(Bundle savedInstanceState) {  
      3. super.onCreate(savedInstanceState);  
      4. this, R.layout.activity_main);  
      5. new UserEntity();  
      6. 34);  
      7. "zhangsan");  
      8. "张三");  
      9.     activityMainBinding.setUser(user);  
      10. }



      运行,显示效果如下:

      android mvvm代码结构目录_xml

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

      1.基本的三目运算


      [java]  view plain  copy



        1. <TextView  
        2. "wrap_content"  
        3. "wrap_content"  
        4. "@{user.username??user.nickname}"/>

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

        2.字符拼接


        [java]  view plain  copy


        1. <TextView  
        2. "wrap_content"  
        3. "wrap_content"  
        4. "@{`username is :`+user.username}"/>


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

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


        [java]  view plain  copy



          1. <TextView  
          2. "wrap_content"  
          3. "wrap_content"  
          4. "@{user.age < 30 ? 0xFF0000FF:0xFFFF0000}"  
          5. "@{String.valueOf(user.age)}"/>


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


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


          2.绑定ImageView

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


          [java]  view plain  copy


          1. @BindingAdapter


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


          [java]  view plain  copy



          1. /**
          2.  * Created by 王松 on 2016/7/31.
          3.  */  
          4. public class User {  
          5. private String username;  
          6. private String userface;  
          7.   
          8. public User() {  
          9.     }  
          10.   
          11. public User(String userface, String username) {  
          12. this.userface = userface;  
          13. this.username = username;  
          14.     }  
          15.   
          16. @BindingAdapter("bind:userface")  
          17. public static void getInternetImage(ImageView iv, String userface) {  
          18.         Picasso.with(iv.getContext()).load(userface).into(iv);  
          19.     }  
          20.   
          21. public String getUserface() {  
          22. return userface;  
          23.     }  
          24.   
          25. public void setUserface(String userface) {  
          26. this.userface = userface;  
          27.     }  
          28.   
          29. public String getUsername() {  
          30. return username;  
          31.     }  
          32.   
          33. public void setUsername(String username) {  
          34. this.username = username;  
          35.     }  
          36. }



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


          [java]  view plain  copy


          1. <?xml version="1.0" encoding="utf-8"?>  
          2. <layout  
          3. "http://schemas.android.com/apk/res/android"  
          4. "http://schemas.android.com/apk/res-auto"  
          5.     >  
          6.   
          7.     <data>  
          8.   
          9.         <variable  
          10. "user"  
          11. "org.lenve.databinding2.User"/>  
          12.     </data>  
          13.   
          14.     <LinearLayout  
          15. "http://schemas.android.com/tools"  
          16. "match_parent"  
          17. "match_parent"  
          18. "vertical"  
          19. "org.lenve.databinding2.MainActivity">  
          20.   
          21.         <ImageView  
          22. "@+id/iv"  
          23. "wrap_content"  
          24. "wrap_content"  
          25. "@{user.userface}"></ImageView>  
          26.   
          27.         <TextView  
          28. "wrap_content"  
          29. "wrap_content"  
          30. "@{user.username}"/>  
          31.     </LinearLayout>  
          32. </layout>


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


          [java]  view plain  copy



            1. @Override  
            2. protected void onCreate(Bundle savedInstanceState) {  
            3. super.onCreate(savedInstanceState);  
            4. this, R.layout.activity_main);  
            5. new User("http://img2.cache.netease.com/auto/2016/7/28/201607282215432cd8a.jpg", "张三"));  
            6. }



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


            android mvvm代码结构目录_java_02

            3.绑定ListView

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

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

            android mvvm代码结构目录_java_03

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


            [java]  view plain  copy



              1. <?xml version="1.0" encoding="utf-8"?>  
              2. <RelativeLayout  
              3. "http://schemas.android.com/apk/res/android"  
              4. "http://schemas.android.com/tools"  
              5. "match_parent"  
              6. "match_parent"  
              7. "org.lenve.databinding3.MainActivity">  
              8.   
              9.     <ListView  
              10. "@+id/lv"  
              11. "match_parent"  
              12. "match_parent"></ListView>  
              13. </RelativeLayout>  
               
              
              主布局很简单,就是一个ListView,再来看看ListView的item布局: 
               
               
                 [java]  
                 view plain 
                  copy 
                 
               
               
              1. <?xml version="1.0" encoding="utf-8"?>  
              2. <layout  
              3. "http://schemas.android.com/apk/res/android"  
              4. "http://schemas.android.com/apk/res-auto"  
              5.     >  
              6.   
              7.     <data>  
              8.   
              9.         <variable  
              10. "food"  
              11. "org.lenve.databinding3.Food"/>  
              12.     </data>  
              13.   
              14.     <RelativeLayout  
              15. "match_parent"  
              16. "96dp"  
              17. "vertical">  
              18.   
              19.         <ImageView  
              20. "@+id/iv"  
              21. "96dp"  
              22. "96dp"  
              23. "6dp"  
              24. "@{food.img}"/>  
              25.   
              26.         <TextView  
              27. "@+id/description"  
              28. "match_parent"  
              29. "wrap_content"  
              30. "8dp"  
              31. "@id/iv"  
              32. "end"  
              33. "3"  
              34. "@{food.description}"/>  
              35.   
              36.         <TextView  
              37. "wrap_content"  
              38. "wrap_content"  
              39. "8dp"  
              40. "@id/iv"  
              41. "true"  
              42. "2dp"  
              43. "@{food.keywords}"  
              44. "bold"/>  
              45.     </RelativeLayout>  
              46. </layout>



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


              [java]  view plain  copy

              1. /**
              2.  * Created by 王松 on 2016/7/31.
              3.  */  
              4. public class Food {  
              5. private String description;  
              6. private String img;  
              7. private String keywords;  
              8. private String summary;  
              9.   
              10. public Food() {  
              11.     }  
              12.   
              13. public Food(String description, String img, String keywords, String summary) {  
              14. this.description = description;  
              15. this.img = img;  
              16. this.keywords = keywords;  
              17. this.summary = summary;  
              18.     }  
              19.   
              20. @BindingAdapter("bind:img")  
              21. public static void loadInternetImage(ImageView iv, String img) {  
              22.         Picasso.with(iv.getContext()).load(img).into(iv);  
              23.     }  
              24.   
              25. public String getDescription() {  
              26. return description;  
              27.     }  
              28.   
              29. public void setDescription(String description) {  
              30. this.description = description;  
              31.     }  
              32.   
              33. public String getImg() {  
              34. return img;  
              35.     }  
              36.   
              37. public void setImg(String img) {  
              38. this.img = img;  
              39.     }  
              40.   
              41. public String getKeywords() {  
              42. return keywords;  
              43.     }  
              44.   
              45. public void setKeywords(String keywords) {  
              46. this.keywords = keywords;  
              47.     }  
              48.   
              49. public String getSummary() {  
              50. return summary;  
              51.     }  
              52.   
              53. public void setSummary(String summary) {  
              54. this.summary = summary;  
              55.     }  
              56. }



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


              [java]  view plain  copy


              1. /**
              2.  * Created by 王松 on 2016/7/31.
              3.  */  
              4. public class MyBaseAdapter<T> extends BaseAdapter {  
              5. private Context context;  
              6. private LayoutInflater inflater;  
              7. private int layoutId;  
              8. private int variableId;  
              9. private List<T> list;  
              10.   
              11. public MyBaseAdapter(Context context, int layoutId, List<T> list, int resId) {  
              12. this.context = context;  
              13. this.layoutId = layoutId;  
              14. this.list = list;  
              15. this.variableId = resId;  
              16.         inflater = LayoutInflater.from(context);  
              17.     }  
              18.   
              19. @Override  
              20.   
              21. public int getCount() {  
              22. return list.size();  
              23.     }  
              24.   
              25. @Override  
              26. public Object getItem(int position) {  
              27. return list.get(position);  
              28.     }  
              29.   
              30. @Override  
              31. public long getItemId(int position) {  
              32. return position;  
              33.     }  
              34.   
              35. @Override  
              36. public View getView(int position, View convertView, ViewGroup parent) {  
              37.         ViewDataBinding dataBinding;  
              38. if (convertView == null) {  
              39. false);  
              40. else{  
              41.             dataBinding = DataBindingUtil.getBinding(convertView);  
              42.         }  
              43.         dataBinding.setVariable(variableId, list.get(position));  
              44. return dataBinding.getRoot();  
              45.     }  
              46. }


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


              [java]  view plain  copy

              1. public class MainActivity extends AppCompatActivity {  
              2.   
              3. private Handler mHandler = new Handler(){  
              4. @Override  
              5. public void handleMessage(Message msg) {  
              6. new MyBaseAdapter<>(MainActivity.this, R.layout.listview_item, foods, org.lenve.databinding3.BR.food);  
              7.             lv.setAdapter(adapter);  
              8.         }  
              9.     };  
              10. private List<Food> foods;  
              11. private ListView lv;  
              12.   
              13. @Override  
              14. protected void onCreate(Bundle savedInstanceState) {  
              15. super.onCreate(savedInstanceState);  
              16.         setContentView(R.layout.activity_main);  
              17.         lv = ((ListView) findViewById(R.id.lv));  
              18.         initData();  
              19.     }  
              20.   
              21. private void initData() {  
              22. new OkHttpClient.Builder().build();  
              23. new Request.Builder().url("http://www.tngou.net/api/food/list?id=1").build();  
              24. new Callback() {  
              25. @Override  
              26. public void onFailure(Call call, IOException e) {  
              27.   
              28.             }  
              29.   
              30. @Override  
              31. public void onResponse(Call call, Response response) throws IOException {  
              32. if (response.isSuccessful()) {  
              33.                     parseJson(response.body().string());  
              34.                 }  
              35.             }  
              36.         });  
              37.     }  
              38.   
              39. private void parseJson(String jsonStr) {  
              40. new ArrayList<>();  
              41. try {  
              42. new JSONObject(jsonStr);  
              43. "tngou");  
              44. for (int i = 0; i < tngou.length(); i++) {  
              45.                 JSONObject item = tngou.getJSONObject(i);  
              46. "description");  
              47. "http://tnfs.tngou.net/image"+item.getString("img");  
              48. "【关键词】 "+item.getString("keywords");  
              49. "summary");  
              50. new Food(description, img, keywords, summary));  
              51.             }  
              52. 0);  
              53. catch (JSONException e) {  
              54.             e.printStackTrace();  
              55.         }  
              56.     }  
              57. }


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

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

              4.点击事件处理

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


              [java]  view plain  copy


              1. <?xml version="1.0" encoding="utf-8"?>  
              2. <layout  
              3. "http://schemas.android.com/apk/res/android"  
              4. "http://schemas.android.com/apk/res-auto"  
              5.     >  
              6.     ....  
              7.     ....  
              8.     <RelativeLayout  
              9. "match_parent"  
              10. "96dp"  
              11. "@{food.onItemClick}"  
              12. "vertical">  
              13.   
              14.         <ImageView  
              15. "@+id/iv"  
              16. "96dp"  
              17. "96dp"  
              18. "6dp"  
              19. "@{food.img}"/>  
              20.         ....  
              21.         ....  
              22.         ....  
              23.     </RelativeLayout>  
              24. </layout>


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


              [java]  view plain  copy



                1. public void onItemClick(View view) {  
                2.     Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();  
                3. }



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

                5. 数据更新处理

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

                1.让实体类继承自BaseObservable

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


                [java]  view plain  copy

                1. public class Food extends BaseObservable {  
                2. private String description;  
                3. private String img;  
                4. private String keywords;  
                5. private String summary;  
                6.   
                7. public Food() {  
                8.     }  
                9.   
                10. public Food(String description, String img, String keywords, String summary) {  
                11. this.description = description;  
                12. this.img = img;  
                13. this.keywords = keywords;  
                14. this.summary = summary;  
                15.     }  
                16.   
                17. @BindingAdapter("bind:img")  
                18. public static void loadInternetImage(ImageView iv, String img) {  
                19.         Picasso.with(iv.getContext()).load(img).into(iv);  
                20.     }  
                21.   
                22. public void onItemClick(View view) {  
                23. //        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();  
                24. "111");  
                25.     }  
                26.   
                27. public void clickKeywords(View view) {  
                28.         Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();  
                29.     }  
                30.   
                31.   
                32. @Bindable  
                33. public String getDescription() {  
                34. return description;  
                35.     }  
                36.   
                37. public void setDescription(String description) {  
                38. this.description = description;  
                39.         notifyPropertyChanged(org.lenve.databinding3.BR.description);  
                40.     }  
                41.   
                42. public String getImg() {  
                43. return img;  
                44.     }  
                45.   
                46. public void setImg(String img) {  
                47. this.img = img;  
                48.     }  
                49.   
                50. public String getKeywords() {  
                51. return keywords;  
                52.     }  
                53.   
                54. public void setKeywords(String keywords) {  
                55. this.keywords = keywords;  
                56.     }  
                57.   
                58. public String getSummary() {  
                59. return summary;  
                60.     }  
                61.   
                62. public void setSummary(String summary) {  
                63. this.summary = summary;  
                64.     }  
                65. }

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

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

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


                [java]  view plain  copy



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



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


                  [java]  view plain  copy


                  1. description.get()


                  写入方式如下:


                  [java]  view plain  copy



                    1. this.description.set(description);



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


                    [java]  view plain  copy


                    1. /**
                    2.  * Created by 王松 on 2016/7/31.
                    3.  */  
                    4. public class Food extends BaseObservable {  
                    5. private final ObservableField<String> description = new ObservableField<>();  
                    6. private final ObservableField<String> img = new ObservableField<>();  
                    7. private final ObservableField<String> keywords = new ObservableField<>();  
                    8. private final ObservableField<String> summary = new ObservableField<>();  
                    9. public Food() {  
                    10.     }  
                    11.   
                    12. public Food(String description, String img, String keywords, String summary) {  
                    13. this.description.set(description);  
                    14. this.keywords.set(keywords);  
                    15. this.img.set(img);  
                    16. this.summary.set(summary);  
                    17.     }  
                    18.   
                    19. @BindingAdapter("bind:img")  
                    20. public static void loadInternetImage(ImageView iv, String img) {  
                    21.         Picasso.with(iv.getContext()).load(img).into(iv);  
                    22.     }  
                    23.   
                    24. public void onItemClick(View view) {  
                    25. //        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();  
                    26. "111");  
                    27.     }  
                    28.   
                    29. public void clickKeywords(View view) {  
                    30.         Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();  
                    31.     }  
                    32.   
                    33.   
                    34. @Bindable  
                    35. public String getDescription() {  
                    36. return description.get();  
                    37.     }  
                    38.   
                    39. public void setDescription(String description) {  
                    40. this.description.set(description);  
                    41.         notifyPropertyChanged(org.lenve.databinding3.BR.description);  
                    42.     }  
                    43.   
                    44. public String getImg() {  
                    45. return img.get();  
                    46.     }  
                    47.   
                    48. public void setImg(String img) {  
                    49. this.img.set(img);  
                    50.     }  
                    51.   
                    52. public String getKeywords() {  
                    53. return keywords.get();  
                    54.     }  
                    55.   
                    56. public void setKeywords(String keywords) {  
                    57. this.keywords.set(keywords);  
                    58.     }  
                    59.   
                    60. public String getSummary() {  
                    61. return summary.get();  
                    62.     }  
                    63.   
                    64. public void setSummary(String summary) {  
                    65. this.summary.set(summary);  
                    66.     }  
                    67. }


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


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

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


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



                    以上。