Android MVVM框架学习总结(二)
2018-03-31 16:04
375 查看
Android MVVM框架学习总结
4. 数据对象
5. 生成Binding
6.设置属性
7.转换器
(1)观察对象(Observable Objects)
A class implementing the Observable interface ,将被允许附加一个listener,来监听对象所有属性的改变
Observable interface有一个机制来添加和删除listeners,但需要通知开发者。为了让开发变得更容易,提供一个基类,BaseObservable,它实现创建listener的注册机制。当属性数据改变时,数据类实现者需要响应通知。这是通过在getter上使用一个注解@Bindable,并在setter中进行通知。
@Bindable 在编译时将生成一个BR class 。BR类文件将生成在moudle的package下。如果数据类的基类不能被改变,Observable interface的实现类可以使用PropertyChangeRegistry存储和有效地通知listeners。
(2)观察属性(ObservableFields)
如果想做比创建上面的观察对象更少的工作,那么可以使用ObservableField 和它的同级的一些类型: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable。它们都是一个包含单一属性的可观察的对象。为避免装箱、拆箱操作,可以在数据类中定义成 public final field …
如下,使用get或set来获取和设置属性值:
(3)观察集合(Observable Collections)
一些应用程序使用更多的动态结构来保存数据。可观察集合允许通过key访问这些数据对象。当key是一个引用类型,如String,就可以用ObservableArrayMap。
在下面的布局中,就可以通过String类型的key来访问map中的数据:
当key是一个Integer时,可用ObservableArrayList:
布局中使用ObservableArrayList:
(1)创建
如前文所述,由相应的布局文件,而生成了相应的binding class。代码中使用它,需要LayoutInflater,如:
如果布局已经inflate了,在某些场景时,可以单独绑定:
有时binding class 不能提前知道。在这种情况下,可以使用DataBindingUtil类创建绑定:
(2)View中使用id
在布局中的每个使用了id的view,都会在binding class中创建出一个同名的public属性。这种绑定机制,比findViewById更快速。
在Activity或者Fragment中可以这样引用,
(3)高级绑定
1)动态Variable
有时,特定的绑定类不会为人所知。例如,一个RecyclerView.Adapter操作的任意布局,不知其特定的绑定类。仍需要通过onBindViewHolder(VH, int)来绑定值。
在下面的例子中,RecyclerView中的所有布局,都绑定了一个”item”,有一个BindingHolder#getBinding() 返回ViewDataBinding 类型:
2)直接绑定
当一个variable or observable发生了改变,绑定框架会安排在下一帧进行视图的改变。然而,有时希望立即发生改变。可以使用executePendingBindings()来强制执行
3)后台线程
你可以改变你的数据模型在一个后台线程,只要它不是一个集合。数据绑定框架将本地化每个变量和属性,以避免任何并发问题。
自动Setters
对于一个attribute,数据绑定框架将试图查找对应的setAttribute()。它的namespace并不重要,只关注attribute的name。如,TextView中的属性android:text使用了表达式,那么框架就会查找setText(String)。如果表达式返回的是int,那么将会查找setText(int)。所以,表达式需要返回正确的类型。数据绑定框架,支持创建一个布局元素(View|ViewGroup)中,并不存在的属性。
如下,生成的binding class中,将生成一个setDrawerListener(listener):
自定义Setters
一些属性需要自定义绑定逻辑。例如,属性android:paddingLeft没有对应的setter方法,而在view中有一个方法为setPadding(left, top, right, bottom)。可以使用@BindingAdapter来自定义一个关于属性android:paddingLeft的setter。例:
还可以用Binding adapter来接收多个参数:
对应的xml绑定:
当ImageView中同时使用了属性String imageUrl和Drawlable error,通过Binding adapter,这时的setter就是 loadImage()。
当从一个绑定表达式返回一个对象,就会有一个setter被采用。该对象将会被转换成setter中的参数类型。
下面的例子,通过ObservableMaps来保存数据:
userMap返回一个对象,该对象将自动转换成setText(CharSequence)中的参数类型。可能会有混乱的参数类型,开发人员需要在表达式中显式cast
自定义转换
有时特定类型之间会自动转换。例如,设置背景:
这里,background的setter的参数类型应该是一个drawable,但color是一个整数。应当有一个转换规则,将int color转换为ColorDrawable。这种转换是通过使用一个@BindingConversion的静态方法来实现的:
注意,转换只发生在setter时期。所以不允许混合类型,如:
4. 数据对象
5. 生成Binding
6.设置属性
7.转换器
Android MVVM框架学习总结
4. 数据对象
任何POJO对象都可以用于数据绑定,但是更改POJO对象,并不会引起UI更新。有三种不同的数据更改通知机制:观察对象,观察字段和观察集合。当其中一个绑定到用户界面的可观察的数据对象,观察到数据对象的属性变化,用户界面将自动更新。(1)观察对象(Observable Objects)
A class implementing the Observable interface ,将被允许附加一个listener,来监听对象所有属性的改变
Observable interface有一个机制来添加和删除listeners,但需要通知开发者。为了让开发变得更容易,提供一个基类,BaseObservable,它实现创建listener的注册机制。当属性数据改变时,数据类实现者需要响应通知。这是通过在getter上使用一个注解@Bindable,并在setter中进行通知。
private static class User extends BaseObservable { private String firstName; private String lastName; @Bindable public String getFirstName() { return this.firstName; } @Bindable public String getLastName() { return this.lastName; } public void setFirstName(String firstName) { this.firstName = firstName; notifyPropertyChanged(BR.firstName); } public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR.lastName); } }
@Bindable 在编译时将生成一个BR class 。BR类文件将生成在moudle的package下。如果数据类的基类不能被改变,Observable interface的实现类可以使用PropertyChangeRegistry存储和有效地通知listeners。
(2)观察属性(ObservableFields)
如果想做比创建上面的观察对象更少的工作,那么可以使用ObservableField 和它的同级的一些类型: ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable。它们都是一个包含单一属性的可观察的对象。为避免装箱、拆箱操作,可以在数据类中定义成 public final field …
private static class User { public final ObservableField<String> firstName = new ObservableField<>(); public final ObservableField<String> lastName = new ObservableField<>(); public final ObservableInt age = new ObservableInt(); }
如下,使用get或set来获取和设置属性值:
user.firstName.set("Google"); int age = user.age.get();
(3)观察集合(Observable Collections)
一些应用程序使用更多的动态结构来保存数据。可观察集合允许通过key访问这些数据对象。当key是一个引用类型,如String,就可以用ObservableArrayMap。
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); user.put("firstName", "Google"); user.put("lastName", "Inc."); user.put("age", 17);
在下面的布局中,就可以通过String类型的key来访问map中的数据:
<data> <import type="android.databinding.ObservableMap"/> <variable name="user" type="ObservableMap<String, Object>"/> </data> … <TextView android:text='@{user["lastName"]}' android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:text='@{String.valueOf(1 + (Integer)user["age"])}' android:layout_width="wrap_content" android:layout_height="wrap_content"/>
当key是一个Integer时,可用ObservableArrayList:
ObservableArrayList<Object> user = new ObservableArrayList<>(); user.add("Google"); user.add("Inc."); user.add(17);
布局中使用ObservableArrayList:
<data> <import type="android.databinding.ObservableList"/> <import type="com.example.my.app.Fields"/> <variable name="user" type="ObservableList<Object>"/> </data> <TextView android:text='@{user[Fields.LAST_NAME]}' android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}' android:layout_width="wrap_content" android:layout_height="wrap_content"/>
5. 生成Binding
生成的绑定类,会链接布局的variables。正如前面所讨论的,绑定的名称和包可能是自定义的的。生成的所有绑定类都 extends ViewDataBinding。(1)创建
如前文所述,由相应的布局文件,而生成了相应的binding class。代码中使用它,需要LayoutInflater,如:
MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater); MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater, viewGroup, false);
如果布局已经inflate了,在某些场景时,可以单独绑定:
MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);
有时binding class 不能提前知道。在这种情况下,可以使用DataBindingUtil类创建绑定:
ViewDataBinding binding = DataBindingUtil.inflate( LayoutInflater, layoutId, parent, attachToParent); ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);
(2)View中使用id
在布局中的每个使用了id的view,都会在binding class中创建出一个同名的public属性。这种绑定机制,比findViewById更快速。
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.firstName}" android:id="@+id/firstName"/>
在Activity或者Fragment中可以这样引用,
binding.firstName
(3)高级绑定
1)动态Variable
有时,特定的绑定类不会为人所知。例如,一个RecyclerView.Adapter操作的任意布局,不知其特定的绑定类。仍需要通过onBindViewHolder(VH, int)来绑定值。
在下面的例子中,RecyclerView中的所有布局,都绑定了一个”item”,有一个BindingHolder#getBinding() 返回ViewDataBinding 类型:
public void onBindViewHolder(BindingHolder holder, int position) { final T item = mItems.get(position); holder.getBinding().setVariable(BR.item, item); holder.getBinding().executePendingBindings(); }
2)直接绑定
当一个variable or observable发生了改变,绑定框架会安排在下一帧进行视图的改变。然而,有时希望立即发生改变。可以使用executePendingBindings()来强制执行
3)后台线程
你可以改变你的数据模型在一个后台线程,只要它不是一个集合。数据绑定框架将本地化每个变量和属性,以避免任何并发问题。
6.设置属性
当view使用了绑定表达式,只要绑定值发生变化,生成的绑定类必须调用相应的setter方法。定制数据绑定框架的方式方法调用设置值。数据绑定框架允许自定义setter方法。自动Setters
对于一个attribute,数据绑定框架将试图查找对应的setAttribute()。它的namespace并不重要,只关注attribute的name。如,TextView中的属性android:text使用了表达式,那么框架就会查找setText(String)。如果表达式返回的是int,那么将会查找setText(int)。所以,表达式需要返回正确的类型。数据绑定框架,支持创建一个布局元素(View|ViewGroup)中,并不存在的属性。
如下,生成的binding class中,将生成一个setDrawerListener(listener):
<android.support.v4.widget.DrawerLayout android:layout_width="wrap_content" android:layout_height="wrap_content" app:scrimColor="@{@color/scrim}" app:drawerListener="@{fragment.drawerListener}"/>
自定义Setters
一些属性需要自定义绑定逻辑。例如,属性android:paddingLeft没有对应的setter方法,而在view中有一个方法为setPadding(left, top, right, bottom)。可以使用@BindingAdapter来自定义一个关于属性android:paddingLeft的setter。例:
@BindingAdapter("android:paddingLeft") public static void setPaddingLeft(View view, int padding) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); }
还可以用Binding adapter来接收多个参数:
@BindingAdapter({"bind:imageUrl", "bind:error"}) public static void loadImage(ImageView view, String url, Drawable error) { Picasso.with(view.getContext()).load(url).error(error).into(view); }
对应的xml绑定:
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}"/>
当ImageView中同时使用了属性String imageUrl和Drawlable error,通过Binding adapter,这时的setter就是 loadImage()。
7.转换器
对象转换当从一个绑定表达式返回一个对象,就会有一个setter被采用。该对象将会被转换成setter中的参数类型。
下面的例子,通过ObservableMaps来保存数据:
<TextView android:text='@{userMap["lastName"]}' android:layout_width="wrap_content" android:layout_height="wrap_content"/>
userMap返回一个对象,该对象将自动转换成setText(CharSequence)中的参数类型。可能会有混乱的参数类型,开发人员需要在表达式中显式cast
自定义转换
有时特定类型之间会自动转换。例如,设置背景:
<View android:background="@{isError ? @color/red : @color/white}" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
这里,background的setter的参数类型应该是一个drawable,但color是一个整数。应当有一个转换规则,将int color转换为ColorDrawable。这种转换是通过使用一个@BindingConversion的静态方法来实现的:
@BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); }
注意,转换只发生在setter时期。所以不允许混合类型,如:
<View android:background="@{isError ? @drawable/error : @color/white}" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
相关文章推荐
- android MVVM框架学习总结(三)
- android MVVM框架学习总结(一)
- Android MVVM框架学习总结(四)
- android快速开发框架 可以一个个学习总结
- Android 框架 MVC、MVP、MVVM学习笔记
- Android系统框架学习总结
- 【项目架构】Android MVP 和MVVM框架模式 学习实例Demo之mvp篇
- android(安卓)开源框架学习总结
- Android二维码ZXing开源框架的学习总结
- Android网络框架volley学习(十一)volley源码解析总结
- nio socket 及其开源框架MINA学习总结(一)
- Android画图学习总结(一)——类的简介
- Android画图学习总结(二)——Bitmap
- Android画图学习总结(四)——Animation(中)
- Android画图学习总结(二)——Bitmap
- Android画图学习总结(四)——Animation(下)
- Android画图学习总结(四)——Animation(下)
- Android画图学习总结(一)——类的简介
- Android学习基础要点总结
- nio socket 及其开源框架MINA学习总结(一)