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

原文: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?在CODE上查看代码片派生到我的代码片
  1. android {  
  2.     ...  
  3.     ...  
  4.     ...  
  5.     dataBinding{  
  6.         enabled true  
  7.     }  
  8. }  

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

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  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 plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <layout  
  3.     xmlns:android="http://schemas.android.com/apk/res/android"  
  4.     >  
  5.   
  6.     <data>  
  7.   
  8.         <variable  
  9.             name="user"  
  10.             type="org.lenve.databinding1.UserEntity"/>  
  11.     </data>  
  12.   
  13.     <LinearLayout  
  14.         xmlns:tools="http://schemas.android.com/tools"  
  15.         android:layout_width="match_parent"  
  16.         android:layout_height="match_parent"  
  17.         android:orientation="vertical"  
  18.         tools:context="org.lenve.databinding1.MainActivity">  
  19.   
  20.         <TextView  
  21.             android:layout_width="wrap_content"  
  22.             android:layout_height="wrap_content"  
  23.             android:text="@{user.username}"/>  
  24.   
  25.         <TextView  
  26.             android:layout_width="wrap_content"  
  27.             android:layout_height="wrap_content"  
  28.             android:text="@{user.nickname}"/>  
  29.   
  30.         <TextView  
  31.             android:layout_width="wrap_content"  
  32.             android:layout_height="wrap_content"  
  33.             android:text="@{String.valueOf(user.age)}"/>  
  34.     </LinearLayout>  
  35. </layout>  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. <data>  
  2.   
  3.     <import type="org.lenve.databinding1.UserEntity"/>  
  4.     <variable  
  5.         name="user"  
  6.         type="UserEntity"/>  
  7. </data>  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. <data>  
  2.   
  3.     <import type="org.lenve.databinding1.UserEntity" alias="Lenve"/>  
  4.     <variable  
  5.         name="user"  
  6.         type="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 plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. DataBindingUtil.setContentView(this, R.layout.activity_main)  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  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?在CODE上查看代码片派生到我的代码片
  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?在CODE上查看代码片派生到我的代码片
  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?在CODE上查看代码片派生到我的代码片
  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?在CODE上查看代码片派生到我的代码片
  1. @BindingAdapter  

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

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

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  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?在CODE上查看代码片派生到我的代码片
  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.   
  9.     <ListView  
  10.         android:id="@+id/lv"  
  11.         android:layout_width="match_parent"  
  12.         android:layout_height="match_parent"></ListView>  
  13. </RelativeLayout>  

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

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

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  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 plaincopy
print?在CODE上查看代码片派生到我的代码片
  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.             dataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, 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 plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. public class MainActivity extends AppCompatActivity {  
  2.   
  3.     private Handler mHandler = new Handler(){  
  4.         @Override  
  5.         public void handleMessage(Message msg) {  
  6.             MyBaseAdapter<Food> adapter = 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.         OkHttpClient client = new OkHttpClient.Builder().build();  
  23.         Request request = new Request.Builder().url("http://www.tngou.net/api/food/list?id=1").build();  
  24.         client.newCall(request).enqueue(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.         foods = new ArrayList<>();  
  41.         try {  
  42.             JSONObject jo = new JSONObject(jsonStr);  
  43.             JSONArray tngou = jo.getJSONArray("tngou");  
  44.             for (int i = 0; i < tngou.length(); i++) {  
  45.                 JSONObject item = tngou.getJSONObject(i);  
  46.                 String description = item.getString("description");  
  47.                 String img = "http://tnfs.tngou.net/image"+item.getString("img");  
  48.                 String keywords = "【关键词】 "+item.getString("keywords");  
  49.                 String summary = item.getString("summary");  
  50.                 foods.add(new Food(description, img, keywords, summary));  
  51.             }  
  52.             mHandler.sendEmptyMessage(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 plaincopy
print?在CODE上查看代码片派生到我的代码片
  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.   
  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.         ....  
  21.         ....  
  22.         ....  
  23.     </RelativeLayout>  
  24. </layout>  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  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?在CODE上查看代码片派生到我的代码片
  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.         setDescription("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 plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. private final ObservableField<String> description = new ObservableField<>();  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. description.get()  

写入方式如下:

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. this.description.set(description);  

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

[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  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.         setDescription("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对上传文件大小的限制,我分三次上传,下载地址如下:


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



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/538914.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打造一款便携版的Sublime Text

https://segmentfault.com/a/1190000000707661 https://www.cnblogs.com/52cik/p/sublime-diy.html 直接安装Sublime Text&#xff0c;不要打开 大家可以参照上文提到的《Sublime Text 全程指引》中的步骤去进行安装。我这里使用的是Sublime Text 2&#xff0c;其实3也是一样的…

confluence创建页面加载缓慢_树莓派4B使用docker安装confluence

说明confluence是一个专业的企业知识管理与协同软件&#xff0c;可以用于构建企业wiki。通过它可以实现团队成员之间的协作和知识共享。现在大多数公司都会部署一套confluence&#xff0c;用作内部wiki。另外confluence也可以作为个人的知识管理工具来用&#xff0c;只需要花10…

matlab粒子加速器仿真,粒子群算法优化PID参数 仿真不出结果 程序如下

用的是《MATLAB智能算法30个案例分析》中的程序1.文件名为PSO_PID.mfunction z PSO_PID(x)assignin(base,Kp,x(1)); % 粒子群依次赋值给Kp 这部分运行结果> PSO_PIDassignin(base,Ki,x(2)); …

CentOS5、6的启动流程

CentOS5/6的启动流程启动流程画了张图,看着更清晰些: (centos7的启动流程变化挺大的,这部分待补充)补充(/etc/rc.d/rc.local 不属于任何服务,为特殊文件,可将不能定义为服务又想开机运行的命令定义在此文件中)添加自定义服务:[rootel5 init.d]# vi /etc/init.d/testsrv #!/bin…

Spark交互式分析平台Apache Zeppelin的安装

Zeppelin介绍 Apache Zeppelin提供了web版的类似ipython的notebook&#xff0c;用于做数据分析和可视化。背后可以接入不同的数据处理引擎&#xff0c;包括Spark, Hive, tajo等&#xff0c;原生支持Scala, Java, shell, markdown等。它的整体展现和使用形式和Databricks Cloud是…

win7 php zend,win7系统打开WZend Studio PHP出错的解决方法

很多朋友安装win7系统后&#xff0c;在使用的过程中会遇到win7系统打开WZend Studio PHP出错的情况&#xff0c;可能有很多用户还是不能自己处理win7系统打开WZend Studio PHP出错的问题&#xff0c;其实简单的来说处理win7系统打开WZend Studio PHP出错的问题只需要按照 1、在…

9个元素换6次达到排序序列_C语言必学的12个排序算法:希尔排序(第3篇)

基本思想希尔排序&#xff08;Shells Sort&#xff09;&#xff0c;以发明人命名&#xff0c;又称为缩小增量排序&#xff0c;也是一种插入排序算法。主要思想&#xff1a;直接插入排序算法时间和待排数据有关&#xff0c;其平均复杂度是O(n^2)&#xff0c;但是在待排数据已经有…

java快捷键禁用_pycharm 掌握这些快捷键,你就是大神!!

最重要的快捷键1. ctrlshiftA:万能命令行 2. shift两次:查看资源文件新建工程第一步操作1. module设置把空包分层去掉,compact empty middle package 2. 设置当前的工程是utf-8,设置的Editor-->File Encodings-->全部改成utf-8,注释1. ctrl/:单行注释光标操作1. ctrlalte…

如何在 5 分钟内读懂区块链的架构思维?

作为入门者&#xff0c;如何在最短的时间了解区块链技术&#xff0c;区块链思维&#xff0c;以及比特币的金融原理呢&#xff1f;本文尝试从比特币的架构设计思维出发&#xff0c;让人从宏观上搞清楚区块链的技术本质。 本文授权转载自阿里技术 作者 | 郑吉 区块链不是一种技术…

arduino 上传项目出错_Arduino多核编程:简单例子

不管你是Arduino领域的新手还是经验丰富的开发人员&#xff0c;很可能你还只使用过单核在进行编程。 这没有什么好笑的---- 事实上&#xff0c;直到几天前我才使用Arduino IDE进行了第一次多核编程。 我和所有其他Arduino粉丝都非常喜欢IDE的易用性以及MicroController 开发所需…

Hadoop-RPC应用demo

Hadoop里的rpc框架可以单独拿出来使用。jar包全在hadoop-common工程里。 导入hadoop-common工程里&#xff08;hadoop-2.7.3为例&#xff09;&#xff1a; hadoop-common-2.7.3.jar \hadoop-2.7.3\share\hadoop\common\lib下的全部jar包 实例 rpc.client 客户端 rpc.pr…

宝塔面板服务器ip地址修改_「网站」快速搭建服务器环境及网站

目录&#xff1a;「NAS」我的搭建NAS全过程在文章开头我想说明的是&#xff0c;此文章中所使用的工具为 BT 面板即宝塔面板&#xff0c;适合小白使用但是对于想要提升个人能力来说&#xff0c; BT 面板并不是一个好选择&#xff0c;而作为新手来说&#xff0c;可以使用该面板进…

杨辉三角python_Python面试150题汇总,都是常问的面试题!

周末&#xff0c;Python面试题每日一题暂停更新&#xff0c;下面把最近整理的1-50篇Python面试文整理一下&#xff0c;平时文章都放在比较末尾&#xff0c;阅读量都不高&#xff0c;相信很多人都没看过&#xff0c;如果对于Python感兴趣的&#xff0c;建议可以认真阅读一下&…

java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.wifi.SCAN_RESULTS flg

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.nokia.wlanapp, PID: 18526java.lang.RuntimeException: Error receiving broadcast Intent { actandroid.net.wifi.SCAN_RESULTS flg0x4000010 (has extras【外部】) } in com.nokia.wlanapp.Receive…

php处理上传文件的步骤,php文件上传步骤

我们在开发网站的时候&#xff0c;经常会遇到需要制作文件上传功能&#xff0c;下面我们就为大家介绍一下php制作文件上传功能的详细步骤。推荐教程&#xff1a;PHP视频教程第一步&#xff1a;创建一个文件上传表单允许用户从表单上传文件是非常有用的。请看下面这个供上传文件…

matlab求傅里叶级数展开式_傅里叶级数:从向量的角度看函数

帮助你理解线性代数与机器学习紧密结合的核心内容下文节选自北大出版社《机器学习线性代数基础》, [遇见]已获授权许可. 这本书不同于传统教材, 从新的角度来介绍线性代数的核心知识, 讲解也很棒, 又刚好参加参加了当当每满100-50的活动, 感兴趣的朋友可以关注下. 傅里叶级数&a…

c++实现超声回波包络检测_超声波物位计的选用

超声波物位计超声波在气体、液体和固体介质中以一定速度传播时因被吸收而衰减&#xff0c;但衰减程度不同&#xff0c;在气体中衰减最大&#xff0c;而在固体中衰减最小&#xff1b;当超声波穿越两种不同介质构成的分界面时会产生反射和折射&#xff0c;且当这两种介质的声阻抗…

Android应用开发:CardView的使用及兼容

原文&#xff1a;http://blog.csdn.net/airk000/article/details/39520977 点击阅读原文 --------------------------------------------------------------- 引言 在Google I/O 2014上&#xff0c;Google公布了Android L Preview版本&#xff0c;此版本的UI有了非常大的改变…

云海技术u盘怎么恢复成普通盘_BITLOCKER加密中断数据无法读取恢复一例

同行求助此问题&#xff0c;密码客户是知道的&#xff0c;输入密码后提示如图&#xff1a;如果点击RESUME则提示如下&#xff1a;无视提示关闭提示框后再次提示分区需要格式化&#xff1a;PC3000 DE中可以添加虚拟驱动器解析BITLOCKER加密的分区&#xff0c;但该例添加虚拟驱动…

git 未能顺利结束(退出码1)

按照这个博客上安装完小乌龟git后&#xff1a;https://blog.csdn.net/jdsjlzx/article/details/51098588win10下安装完乌龟git后无法上传文件进行文件上传时出现错误如下&#xff1a;git 未能顺利结束&#xff08;退出码1&#xff09;&#xff08;922ms2018/4/17 22&#xff1a…