@zongwu
2017-01-12T07:46:53.000000Z
字数 7757
阅读 422
技术交流
The Bindable annotation should be applied to any getter accessor method of an Observable class.
@Bindable
用于修饰方法
或变量
。
Observable
接口提供给开发者添加/移除监听者的机制。为了使开发更便捷我们创建了BaseObservable
类,它已经实现了Observable
接口中的注册监听者的机制。
继承自BaseObservable
的数据类仍需手动的通知监听者们数据变更。因而,你可以在setter
方法中通知变更,在getter
方法中标记注解@Bindable
。
注解@Bindable
在编译期间生成一个BR
类以此持有对应的实例,作用同R
文件。
private static class User extends BaseObservable {
private String firstName;
@Bindable
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
}
BindingAdapter is applied to methods that are used to manipulate how values with expressions are set to views.
@BindingAdapter
用于修饰方法
。
一些属性需要定制绑定逻辑,一个用@BindingAdapter
修饰的静态方法可以自定义属性的setter
操作。
android
自身实现了大量的Adapter
,你可以在项目module
的android.databinding.adapters
包下找到这些代码。
public class CardViewBindingAdapter {
@BindingAdapter("contentPadding")
public static void setContentPadding(CardView view, int padding) {
view.setContentPadding(padding, padding, padding, padding);
}
}
1、默认的你的自定义的命名空间,在匹配时会被忽略。
@BindingAdapter("contentPadding")
2、允许重写android的命名空间。
@BindingAdapter("android:contentPadding")
app:contentPadding
与android:contentPadding
处理行为可以不一样。
app:contentPadding
与custom:contentPadding
处理行为是一致的。(仅android
是特殊的命名空间)。
需要注意,当你创建的适配器属性与系统默认的产生冲突时,你的自定义适配器将会覆盖掉系统原先定义的注解,这将会产生一些意外的问题。
假设需要对下面接口,做适配。
public interface ILogAction{
void login();
void logout();
}
则需要一个方法一个接口
,这么做的原因是避免login()
的修改影响到logout()
。所以根据业务需要,可能需要排列组合适配这两个接口。
1、适配 login
2、适配 logout
3、适配 login + logout
@BindingBuildInfo(
buildId="3fefc6ba-1e95-4dcf-8ffa-278fe0f449bd",
modulePackage="com.ipudong.library",
sdkRoot="/Users/robert/Library/Android/sdk",
layoutInfoDir="/Users/robert/android/develops/pudong-d-android/lib_basic/build/intermediates/data-binding-info/debug",
exportClassListTo="/Users/robert/android/develops/pudong-d-android/lib_basic/build/intermediates/data-binding-info/debug/_generated.txt",
isLibrary=true,
minSdk=14,
enableDebugLogs=false,
printEncodedError=true
)
public class DataBindingInfo {}
在SOURCE
阶段会自动生成DataBindingInfo.class
,并标记注解如上。
Annotate methods that are used to automatically convert from the expression type to the value used in the setter.
有时候会遇到类型不匹配的问题,比如R.color.white
是int
,但是通过Data Binding赋值给android:background
属性后,需要把int
转换为ColorDrawable
。
@BindingConversion
public static Drawable convertColorToDrawable(int drawable) {
return new ColorDrawable(drawable);
}
Used within an BindingMethods annotation to describe a renaming of an attribute to the setter used to set that attribute.
Used to enumerate attribute-to-setter renaming.
@BindingMethods
用于修饰类。
一些属性虽然拥有setters
但是并不与名字相匹配,这些方法的属性可以通过 @BindingMethod && @BindingMethods
注释 setters
。
@BindingMethods({
@BindingMethod(type = "android.widget.ImageView",
attribute = "android:tint",
method = "setImageTintList"),
})
开发人员不太可能需要重命名 setters
,因为android框架属性已经实现了这一部分。
InverseBindingAdapter is associated with a method used to retrieve the value for a View when setting values gathered from the View.
InverseBindingAdapter is associated with a method used to retrieve the value for a View when setting values gathered from the View. This is similar to BindingAdapters:
@InverseBindingAdapter(attribute = "android:text", event = "android:textAttrChanged")
public static String captureTextValue(TextView view, CharSequence originalValue) {
CharSequence newValue = view.getText();
CharSequence oldValue = value.get();
if (oldValue == null) {
value.set(newValue);
} else if (!contentEquals(newValue, oldValue)) {
value.set(newValue);
}
}
he default value for event is the attribute name suffixed with "AttrChanged". In the above example, the default value would have been android:textAttrChanged
even if it wasn't provided.
The event attribute is used to notify the data binding system that the value has changed. The developer will typically create a BindingAdapter to assign the event. For example:
@BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
"android:afterTextChanged", "android:textAttrChanged"},
requireAll = false)
public static void setTextWatcher(TextView view, final BeforeTextChanged before,
final OnTextChanged on, final AfterTextChanged after,
final InverseBindingListener textAttrChanged) {
TextWatcher newValue = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (on != null) {
on.onTextChanged(s, start, before, count);
}
if (textAttrChanged != null) {
textAttrChanged.onChange();
}
}
}
TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
if (oldValue != null) {
view.removeTextChangedListener(oldValue);
}
view.addTextChangedListener(newValue);
}
Like BindingAdapters, InverseBindingAdapter methods may also take DataBindingComponent as the first parameter and may be an instance method with the instance retrieved from the DataBindingComponent.
InverseBindingListener
is useful. See InverseBindingListener
InverseBindingMethod is used to identify how to listen for changes to a View property and which getter method to call.
InverseBindingMethod is used to identify how to listen for changes to a View property and which getter method to call. InverseBindingMethod should be associated with any class as part of InverseBindingMethods.
@InverseBindingMethods({@InverseBindingMethod(
type = android.widget.TextView.class,
attribute = "android:text",
event = "android:textAttrChanged",
method = "getText")})
public class MyTextViewBindingAdapters { ... }
method is optional. If it isn't provided, the attribute name is used to find the method name, either prefixing with "is" or "get". For the attribute android:text, data binding will search for a public CharSequence getText() method on TextView.
event is optional. If it isn't provided, the event name is assigned the attribute name suffixed with AttrChanged. For the android:text attribute, the default event name would be android:textAttrChanged. The event should be set using a BindingAdapter. For example:
@BindingAdapter(value = {"android:beforeTextChanged", "android:onTextChanged",
"android:afterTextChanged", "android:textAttrChanged"},
requireAll = false)
public static void setTextWatcher(TextView view, final BeforeTextChanged before,
final OnTextChanged on, final AfterTextChanged after,
final InverseBindingListener textAttrChanged) {
TextWatcher newValue = new TextWatcher() {
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (on != null) {
on.onTextChanged(s, start, before, count);
}
if (textAttrChanged != null) {
textAttrChanged.onChange();
}
}
}
TextWatcher oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher);
if (oldValue != null) {
view.removeTextChangedListener(oldValue);
}
view.addTextChangedListener(newValue);
}
Used to enumerate attribute, getter, and event association.
baseLibrary-2.1.0-rc1.jar
作为运行时类库被打进APK中;
DataBinderPlugin(gradle plugin)
在编译期使用,利用gradle-api(之前叫transform-api,1.5生,2.0改名)处理xml文件,生成DataBindingInfo.java;
compiler-2.1.0-rc1.jar
在编译器使用,入口类继承自AbstractProcessor,用于处理注解,并生成Binding类,DataBindingCompoent.java,DataBinderMapper.java类;
compilerCommon-2.1.0-rc1.jar
被DataBinderPlugin和compiler-2.1.0-rc1.jar所依赖
aapt或者gradle执行时,都会触发资源处理。
在资源处理过程中,DataBinding都会扫描一遍现有的资源,生成不包含的data-binding-layout-out以及DataBinding所需要的data-binding-info;
在完成资源处理后,aapt或者gradle-api都会去执行DataBindingInfo.class生成操作,把相关的信息写入DataBindingInfo.class的@BindingBuildInfo注解中;
生成@BindingBuildInfo注解,或者code中发现有新的注解写入,AbstractProcessor注解处理器就开始执行注解处理。
DataBinding中有一个ProcessDataBinding.java类专门来处理DataBinding相关的注解;
ProcessDataBinding中处理注解永远会按顺执行3步,ProcessMethodAdapter,ProcessExpressions,ProcessBindable。
每次执行都会从磁盘反序列化对应的bin文件,然后往bin中写入新的,完成后再序列化到磁盘;
执行ProcessMethodAdapter生成DataBindingComponents.class;
执行ProcessExpressions生成ViewDataBinding.class子类(ActivityDetail2Binding.class),并触发DataBindingMapper.class更新;
执行ProcessBindable生成BR.class,并触发DataBindingMapper.class更新;
参考链接:
http://www.jianshu.com/p/eb29c691d370
https://developer.android.com/topic/libraries/data-binding/index.html
https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html