原文:http://blog.csdn.net/u012702547/article/details/52077515

---------------------------------------------------------

MVP可以结合android的DataBinding

-------------------------以下转载---------------

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 plaincopy print?
  1. android {
  2. ...
  3. ...
  4. ...
  5. dataBinding{
  6. enabled true
  7. }
  8. }

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

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

[java] view plaincopy print?
  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. public UserEntity() {
  9. }
  10. public int getAge() {
  11. return age;
  12. }
  13. public void setAge(int age) {
  14. this.age = age;
  15. }
  16. public String getNickname() {
  17. return nickname;
  18. }
  19. public void setNickname(String nickname) {
  20. this.nickname = nickname;
  21. }
  22. public String getUsername() {
  23. return username;
  24. }
  25. public void setUsername(String username) {
  26. this.username = username;
  27. }
  28. public UserEntity(int age, String nickname, String username) {
  29. this.age = age;
  30. this.nickname = nickname;
  31. this.username = username;
  32. }
  33. }

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

[java] view plaincopy print?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <layout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. >
  5. <data>
  6. <variable
  7. name="user"
  8. type="org.lenve.databinding1.UserEntity"/>
  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.databinding1.MainActivity">
  16. <TextView
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:text="@{user.username}"/>
  20. <TextView
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:text="@{user.nickname}"/>
  24. <TextView
  25. android:layout_width="wrap_content"
  26. android:layout_height="wrap_content"
  27. android:text="@{String.valueOf(user.age)}"/>
  28. </LinearLayout>
  29. </layout>

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

[java] view plaincopy print?
  1. <data>
  2. <import type="org.lenve.databinding1.UserEntity"/>
  3. <variable
  4. name="user"
  5. type="UserEntity"/>
  6. </data>

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

[java] view plaincopy print?
  1. <data>
  2. <import type="org.lenve.databinding1.UserEntity" alias="Lenve"/>
  3. <variable
  4. name="user"
  5. type="Lenve"/>
  6. </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 plaincopy print?
  1. DataBindingUtil.setContentView(this, R.layout.activity_main)

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

[java] view plaincopy print?
  1. ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

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

[java] view plaincopy print?
  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
  5. UserEntity user = new UserEntity();
  6. user.setAge(34);
  7. user.setUsername("zhangsan");
  8. user.setNickname("张三");
  9. activityMainBinding.setUser(user);
  10. }

运行,显示效果如下:

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

1.基本的三目运算

[java] view plaincopy print?
  1. <TextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. android:text="@{user.username??user.nickname}"/>

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

2.字符拼接

[java] view plaincopy print?
  1. <TextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. android:text="@{`username is :`+user.username}"/>

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

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

[java] view plaincopy print?
  1. <TextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"
  4. android:background="@{user.age &lt; 30 ? 0xFF0000FF:0xFFFF0000}"
  5. android:text="@{String.valueOf(user.age)}"/>

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

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

2.绑定ImageView

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

[java] view plaincopy print?
  1. @BindingAdapter

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

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

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

[java] view plaincopy print?
  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. >
  6. <data>
  7. <variable
  8. name="user"
  9. type="org.lenve.databinding2.User"/>
  10. </data>
  11. <LinearLayout
  12. xmlns:tools="http://schemas.android.com/tools"
  13. android:layout_width="match_parent"
  14. android:layout_height="match_parent"
  15. android:orientation="vertical"
  16. tools:context="org.lenve.databinding2.MainActivity">
  17. <ImageView
  18. android:id="@+id/iv"
  19. android:layout_width="wrap_content"
  20. android:layout_height="wrap_content"
  21. app:userface="@{user.userface}"></ImageView>
  22. <TextView
  23. android:layout_width="wrap_content"
  24. android:layout_height="wrap_content"
  25. android:text="@{user.username}"/>
  26. </LinearLayout>
  27. </layout>

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

[java] view plaincopy print?
  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. ActivityMainBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
  5. dataBinding.setUser(new User("http://img2.cache.netease.com/auto/2016/7/28/201607282215432cd8a.jpg", "张三"));
  6. }

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

3.绑定ListView

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

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

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

[java] view plaincopy print?
  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>

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

[java] view plaincopy print?
  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. >
  6. <data>
  7. <variable
  8. name="food"
  9. type="org.lenve.databinding3.Food"/>
  10. </data>
  11. <RelativeLayout
  12. android:layout_width="match_parent"
  13. android:layout_height="96dp"
  14. android:orientation="vertical">
  15. <ImageView
  16. android:id="@+id/iv"
  17. android:layout_width="96dp"
  18. android:layout_height="96dp"
  19. android:padding="6dp"
  20. app:img="@{food.img}"/>
  21. <TextView
  22. android:id="@+id/description"
  23. android:layout_width="match_parent"
  24. android:layout_height="wrap_content"
  25. android:layout_marginLeft="8dp"
  26. android:layout_toRightOf="@id/iv"
  27. android:ellipsize="end"
  28. android:maxLines="3"
  29. android:text="@{food.description}"/>
  30. <TextView
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:layout_marginLeft="8dp"
  34. android:layout_toRightOf="@id/iv"
  35. android:layout_alignParentBottom="true"
  36. android:layout_marginBottom="2dp"
  37. android:text="@{food.keywords}"
  38. android:textStyle="bold"/>
  39. </RelativeLayout>
  40. </layout>

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

[java] view plaincopy print?
  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. public Food() {
  10. }
  11. public Food(String description, String img, String keywords, String summary) {
  12. this.description = description;
  13. this.img = img;
  14. this.keywords = keywords;
  15. this.summary = summary;
  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. public String getDescription() {
  22. return description;
  23. }
  24. public void setDescription(String description) {
  25. this.description = description;
  26. }
  27. public String getImg() {
  28. return img;
  29. }
  30. public void setImg(String img) {
  31. this.img = img;
  32. }
  33. public String getKeywords() {
  34. return keywords;
  35. }
  36. public void setKeywords(String keywords) {
  37. this.keywords = keywords;
  38. }
  39. public String getSummary() {
  40. return summary;
  41. }
  42. public void setSummary(String summary) {
  43. this.summary = summary;
  44. }
  45. }

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

[java] view plaincopy print?
  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. public MyBaseAdapter(Context context, int layoutId, List<T> list, int resId) {
  11. this.context = context;
  12. this.layoutId = layoutId;
  13. this.list = list;
  14. this.variableId = resId;
  15. inflater = LayoutInflater.from(context);
  16. }
  17. @Override
  18. public int getCount() {
  19. return list.size();
  20. }
  21. @Override
  22. public Object getItem(int position) {
  23. return list.get(position);
  24. }
  25. @Override
  26. public long getItemId(int position) {
  27. return position;
  28. }
  29. @Override
  30. public View getView(int position, View convertView, ViewGroup parent) {
  31. ViewDataBinding dataBinding;
  32. if (convertView == null) {
  33. dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, false);
  34. }else{
  35. dataBinding = DataBindingUtil.getBinding(convertView);
  36. }
  37. dataBinding.setVariable(variableId, list.get(position));
  38. return dataBinding.getRoot();
  39. }
  40. }

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

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

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

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

4.点击事件处理

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

[java] view plaincopy print?
  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. >
  6. ....
  7. ....
  8. <RelativeLayout
  9. android:layout_width="match_parent"
  10. android:layout_height="96dp"
  11. android:onClick="@{food.onItemClick}"
  12. android:orientation="vertical">
  13. <ImageView
  14. android:id="@+id/iv"
  15. android:layout_width="96dp"
  16. android:layout_height="96dp"
  17. android:padding="6dp"
  18. app:img="@{food.img}"/>
  19. ....
  20. ....
  21. ....
  22. </RelativeLayout>
  23. </layout>

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

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

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

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

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

[java] view plaincopy print?
  1. private final ObservableField<String> description = new ObservableField<>();

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

[java] view plaincopy print?
  1. description.get()

写入方式如下:

[java] view plaincopy print?
  1. this.description.set(description);

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

[java] view plaincopy print?
  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. public Food(String description, String img, String keywords, String summary) {
  12. this.description.set(description);
  13. this.keywords.set(keywords);
  14. this.img.set(img);
  15. this.summary.set(summary);
  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. public void onItemClick(View view) {
  22. //        Toast.makeText(view.getContext(), getDescription(), Toast.LENGTH_SHORT).show();
  23. setDescription("111");
  24. }
  25. public void clickKeywords(View view) {
  26. Toast.makeText(view.getContext(), getKeywords(), Toast.LENGTH_SHORT).show();
  27. }
  28. @Bindable
  29. public String getDescription() {
  30. return description.get();
  31. }
  32. public void setDescription(String description) {
  33. this.description.set(description);
  34. notifyPropertyChanged(org.lenve.databinding3.BR.description);
  35. }
  36. public String getImg() {
  37. return img.get();
  38. }
  39. public void setImg(String img) {
  40. this.img.set(img);
  41. }
  42. public String getKeywords() {
  43. return keywords.get();
  44. }
  45. public void setKeywords(String keywords) {
  46. this.keywords.set(keywords);
  47. }
  48. public String getSummary() {
  49. return summary.get();
  50. }
  51. public void setSummary(String summary) {
  52. this.summary.set(summary);
  53. }
  54. }

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

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

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

本文共涉及到三个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

以上。

-------------

更多的Java,Angular,Android,大数据,J2EE,Python,数据库,Linux,Java架构师,:

http://www.cnblogs.com/zengmiaogen/p/7083694.html

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

  1. python大游戏_玩游戏就能学Python?太炫酷了!

    原标题:玩游戏就能学Python?太炫酷了! 要说现在最火的语言,那一定是Python了. 各种排行榜里,Python的排名都是蹭蹭蹭地往上涨.Python也确实是最适合新手入门的语言了,语法简单,应 ...

  2. iOS OC mvvm开发模式

    相信大家对MVC开发都已经不陌生了,最经典开发模式 MVC构成: M:model也就是数据模型 V:View视图 C:Controller控制器 Model和View是相互独立的.View只负责页面展 ...

  3. android仿IT之家、炫酷水波纹、Kotlin MVP项目、后台模拟点击、蜂巢迷宫小游戏等源码...

    Android精选源码 Android 炫酷的多重水波纹源码 Android开发一款基于行为识别和个性化推荐的智能推荐APP 仿IT之家Android源码 android判断App位于前台或者后台源码 ...

  4. android仿IT之家、炫酷水波纹、Kotlin MVP项目、后台模拟点击、蜂巢迷宫小游戏等源码

    Android精选源码 Android 炫酷的多重水波纹源码 Android开发一款基于行为识别和个性化推荐的智能推荐APP 仿IT之家Android源码 android判断App位于前台或者后台源码 ...

  5. android录音波浪动画_Android实现炫酷的波浪下载Loading动画

    1. 简介和效果分析 一直都觉得有很多loading动画挺炫酷的,然后自己看过一些之后也想实现一个,加强一下对绘制view的练习,能力有限,很多地方的实现的有欠考虑和逻辑优化,不管怎么样画了两天还是把 ...

  6. Android 自带描边颜色渐变炫酷进度条,面试必知必会

    3. 画第三个圆角矩形作为进度条的最外层(进度层)盖在背景层之上 4. 描边层和背景层颜色可用纯色,进度层为了炫酷可用渐变色 这是实现该自带描边颜色渐变进度条的原理,也是在PS中实现该效果的步骤,同样 ...

  7. 【Android珍藏】推荐10个炫酷的开源库

    前言 技术群里面经常有人问到一些炫酷的UI效果实现方法,有时候我都是给一个相同或者相似效果的Github链接,有同学私信给我说,怎么这些效果你都能找到?你是怎么搜索的,或者有其他什么秘方?会利用Goo ...

  8. android 天气动画,为app制作炫酷天气动画 – WeatherView

    WeatherView 从1.1.0版本开始这个库使用了一个不同的setter结构. WeatherView是一个为app制作一个炫酷天气动画的Android库. Setup Android Stud ...

  9. android 动画开源框架,21款炫酷动画开源框架,照亮你的APP

    前言 最近对应用的UI视觉效果突然来了兴致,所以找了一些合适开源控件,这样更加省时,再此分享给大家,希望能对大家有帮助,此博文介绍的都是UI上面的框架. 1.Side-Menu.Android 分类侧 ...

最新文章

  1. C++和服务器交互的几个文件代码
  2. Android -- isInEditMode
  3. 洛谷 P1202 模拟 - 黑色星期五 Friday the Thirteenth
  4. 复制构造函数的用法及出现迷途指针问题
  5. 01.神经网络和深度学习 W4.深层神经网络
  6. Apache kafka原理与特性(0.8V)
  7. TensorFlow windows安装
  8. System.Drawing.Text.TextRenderingHint 的几种效果
  9. a标签写链接地址跳转到下载企业微信app页面
  10. 焦点图,带数字显示,支持常见浏览器
  11. 程序员,小红书王牌生活记录家。这是一篇记录程序员生涯的笔记。
  12. vc html插件,VC++6.0插件系列(绝对经典)
  13. 2022-2028年中国企业总部管理行业市场专项调查及投资前景分析报告
  14. 执行maven install命令报java不支持diamond语法
  15. C语言中有关字符串的库函数(3)
  16. python爬虫详细-Python爬虫|Python爬虫入门(一):爬虫基本结构简单实例
  17. 3. pandas基础
  18. 显示器的分辨率,字体像素
  19. leetcode 78.不含重复元素数组的子集
  20. maven 树 查看依赖

热门文章

  1. java 集合modcount_源码|jdk源码之LinkedList与modCount字段
  2. Linux升级glibc版本汉字乱码,Linux CentOS6升级glibc库过程
  3. ajax跨域只能是get,jsonp跨域请求只能get变相解决方案
  4. oracle判断数据出现交叉,Oracle!你必须要知道的Knowledge points(一)
  5. 操作系统原理:进程 PV 操作如何计算?全网最全三种前驱图计算类型总结
  6. React中使用Ant Table组件
  7. redhat enterprise linux 哪个版本好,Red Hat Enterprise Linux 版本显示中(Santiago)是啥意思?...
  8. vue 仿二手交易app_Vue项目开发-仿蘑菇街电商APP
  9. HDL的综合和c语言的编译区别,C语言与verilog 的区别及相互转化
  10. java rc2加密_急求java RC2加密算法