熊猫儿 发表于 2016-9-15 23:12

3.在父类ViewDataBinding中经过一些的判断,调用到ActivityDetail3Binding中的executeBindings,在executeBindings中根据dirtyFlags执行不同的View属性赋值,以下所有ActivityDetail3Binding相关代码都是编译器自动生成的public class ActivityDetail3Binding extends ViewDataBinding{    ...    protected void executeBindings() {      long dirtyFlags = 0L;      synchronized(this) {            dirtyFlags = this.mDirtyFlags;            this.mDirtyFlags = 0L;      }      Drawable avatarAdapter = null;      ModelAdapter adapter = this.mAdapter;      String descAdapter = null;      String nameAdapter = null;      ActivityDetail3Binding.OnClickListenerImpl androidViewViewOnCli = null;      String actionTextAdapter = null;      int visibility = this.mVisibility;      if((dirtyFlags & 5L) != 0L && adapter != null) {            avatarAdapter = adapter.getAvatar();            descAdapter = adapter.getDesc();            nameAdapter = adapter.getName();            androidViewViewOnCli = (this.mAndroidViewViewOnCl == null?(this.mAndroidViewViewOnCl = new ActivityDetail3Binding.OnClickListenerImpl()):this.mAndroidViewViewOnCl).setValue(adapter);            actionTextAdapter = adapter.actionText();      }      if((dirtyFlags & 6L) != 0L) {            ;      }      if((dirtyFlags & 5L) != 0L) {            TextViewBindingAdapter.setText(this.detailActionButton, actionTextAdapter);            this.detailActionButton.setOnClickListener(androidViewViewOnCli);            ImageViewBindingAdapter.setImageDrawable(this.detailAvatar, avatarAdapter);            TextViewBindingAdapter.setText(this.detailDesc, descAdapter);            TextViewBindingAdapter.setText(this.detailName, nameAdapter);      }      if((dirtyFlags & 6L) != 0L) {            this.detailAvatar.setVisibility(visibility);            this.detailDesc.setVisibility(visibility);            this.detailName.setVisibility(visibility);      }    }    ...}

熊猫儿 发表于 2016-9-15 23:14

至此,完成了View数据的填充分析。4 Binding自动生成的ViewDataBinding类(例如ActivityDetail3Binding)内包含了Model + View,是MVVM中的MV的概念。第2章的View注入,第3章的View赋值都是铺垫,他们最后都是为Binding操作进行服务。目前谷歌已经支持双向Binding,但上文已经提到,目前资料比较少。本文只关注单向的Binding,即:Model的变化,自动同步到View上。4.1 使用ObservableField目前所提供的ObservableField有:
Observable类型对应原类型
ObservableArrayListArrayList
ObservableArrayMapArrayMap
ObservableBooleanboolean
ObservableBytebyte
ObservableCharchar
ObservableFloatfloat
ObservableDoubledouble
ObservableLonglong
ObservableIntint
ObservableParcelable
ObservableField
本文使用简单的ObservableInt作为示例,解决visibility的单项绑定问题。
* 改造activity_detail4.xml:定义类型为ObservableInt的variable,name为visibility,随后赋值给ImageView的android:visibility,示例如下:<layout xmlns:android="http://schemas.android.com/apk/res/android">    <data>      <variable name="visibility" type="android.databinding.ObservableInt"/>    </data>    <LinearLayout      android:orientation="vertical" android:layout_width="match_parent"      android:layout_height="match_parent">       ...      <ImageView            android:visibility="@{visibility.get()}"            android:id="@+id/detail_avatar"            android:layout_gravity="center"            android:layout_marginTop="-33dp"            android:layout_width="66dp"            android:layout_height="66dp" />      ...    </LinearLayout></layout>

熊猫儿 发表于 2016-9-16 21:16


[*]改造DetailActivity4.java,只需要在onCreate时把visibility赋值给binding(ActivityDetail4Binding)即可,后面对visibility的操作,就会更新到view上,示例代码如下:
public class DetailActivity4 extends AppCompatActivity {    ActivityDetail4Binding binding;    ObservableInt visibility = new ObservableInt();    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {      super.onCreate(savedInstanceState);      binding = DataBindingUtil.setContentView(this,R.layout.activity_detail4,new MyComponent());      binding.setVisibility(visibility);      login();    }    private void login(){fill(User.newInstance());}    private void logout(){ fill(null); }    private void fill(final User user){      visibility.set(user != null ? View.VISIBLE : View.GONE);      ....    }    ....}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
4.2 ActivityDetail4Binding中单向绑定相关的代码分析与给ActivityDetail4Binding直接set纯Model不同,所有的ObservableField都实现了Observable接口,只要实现了Observable接口,都是单向Binding类型,所以ActivityDetail4Binding中的setVisibility多加了一行代码:this.updateRegistration(1, visibility),其中1为propertyId,目前一共自动生成了2个,0为adatper,1为visibility,代码如下:public class ActivityDetail4Binding extends ViewDataBinding {    ...    public void setVisibility(ObservableInt visibility) {      this.updateRegistration(1, visibility);      this.mVisibility = visibility;      synchronized(this) {            this.mDirtyFlags |= 2L;      }      this.notifyPropertyChanged(3);      super.requestRebind();    }    ...}

熊猫儿 发表于 2016-9-16 21:17

updateRegistration函数为ViewDataBinding中的函数,会根据 Observable、ObservableList、ObservableMap三种类型,分别创建对应的Listener。ObservableInt为Observable,所以会使用CREATE_PROPERTY_LISTENER,在registerTo函数中创建WeakPropertyListener,
代码如下:public abstract class ViewDataBinding extends BaseObservable {    ...    private boolean updateRegistration(int localFieldId, Object observable,            CreateWeakListener listenerCreator) {      if (observable == null) {            return unregisterFrom(localFieldId);      }      WeakListener listener = mLocalFieldObservers;      if (listener == null) {            registerTo(localFieldId, observable, listenerCreator);            return true;      }      if (listener.getTarget() == observable) {            return false;//nothing to do, same object      }      unregisterFrom(localFieldId);      registerTo(localFieldId, observable, listenerCreator);      return true;    }    ...}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
在WeakPropertyListener的mListener有个setTarget函数,这个函数会向mObservable(即外面传进来的visibility)注册一个监听器,如果visibility值发生变化,这个listener就会得到通知,回调到WeakPropertyListener的onPropertyChanged,接着通知到binding(ActivityDetail4Binding)的handleFieldChange,在handleFieldChange中调用了ActivityDetail4Binding的onFieldChange函数,如果返回值为true,则在handleFieldChange中调用requestRebind(),通知View进行赋值更新界面,onFieldChange相关代码如下:public abstract class ViewDataBinding extends BaseObservable {    ...   private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {      boolean result = onFieldChange(mLocalFieldId, object, fieldId);      if (result) {            requestRebind();      }    }    ...}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
public class ActivityDetail4Binding extends ViewDataBinding {    ...    protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {      switch(localFieldId) {      case 0:            return this.onChangeAdapter((ModelAdapter)object, fieldId);      case 1:            return this.onChangeVisibility((ObservableInt)object, fieldId);      default:            return false;      }    }    ...}

熊猫儿 发表于 2016-9-16 21:18

4.3 Observable Objects与4.1 ObservableField类似,可以改造一下ModelAdapter:为getter方法增加@Bindable注解,为setter方法增加notifyPropertyChanged(com.asha.demo.BR.name)通知。其中,BR是根据@Bindalbe自动生成的类,给getter方法增加@Bindable注解后,BR文件自动会生成一个整型的name。改造后代码如下:public class DetailActivity4 extends AppCompatActivity {    ActivityDetail4Binding binding;    ObservableInt visibility = new ObservableInt();    public class ModelAdapter extends BaseObservable{      private User user;      public ModelAdapter(User user) {            this.user = user;      }      ...      @Bindable      public String getName(){            return user != null ? user.getName() : null;      }      public void setName(String name){            if (user != null) user.setName(name);            notifyPropertyChanged(com.asha.demo.BR.name);      }      ...    }    ...}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
随后,在DetailActivity4.java中调用测试代码,执行完会在1秒后改变adapter上的name值,并且同步到View上,测试代码如下:binding.detailActionButton.postDelayed(new Runnable() {    @Override    public void run() {      adapter.setName("haha");    }},1000);
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
具体原理与4.1类似,不再赘述。5 layout.xml中View属性的setter在下述示例中,detail_name这个TextView想把adapter.name赋值给自身的text属性,就需要调用textView.setText(String)方法,这个方法就是View属性的setter方法。<TextView    android:text="@{adapter.name}"    android:id="@+id/detail_name"    android:layout_width="wrap_content"    android:layout_height="wrap_content" />
[*]1
[*]2
[*]3
[*]4
[*]5
5.1 @BindingAdapter上述的setter方法,Data Binding库帮我们实现了大部分默认方法,具体方法参见

熊猫儿 发表于 2016-9-16 21:19

android.databinding.adapters包下的类,下图为ViewBindingAdatper具体实现,
http://img.blog.csdn.net/20160504094202056
其中setter方法都为static方法,第一个参数都为自身的实例,后面为xml中传入的参数,只要加入@BindingAdapter注解,编译器就会全局搜索保存在一个temp文件中,并在生成类似ActivityDetail4Binding过程中去查找所需的setter方法的。如果需要自定义,只需要在任意app代码中定义@BindingAdapter即可,例如:public class DetailActivity4 extends AppCompatActivity {    @BindingAdapter("android:alpha")    public static void globalSetAlpha(View view, float alpha) {      view.setAlpha(alpha);    }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
5.2 DataBindingComponent很多情况下只是某个Binding文件(例如ActivityDetail4Binding)需要自定义setter方法,这个时候就需要使用DataBindingComponent,
* 首先,定义一个MyComponent,public class MyComponent implements android.databinding.DataBindingComponent {    @BindingAdapter("android:alpha")    public void setAlpha(View view, float alpha) {      view.setAlpha(0.5f);    }    @Override    public MyComponent getMyComponent() {      return new MyComponent();    }}

熊猫儿 发表于 2016-9-16 21:20


[*]接着,在生成Binding对象时传入这个DataBindingComponent实例,代码如下:
@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    binding = DataBindingUtil.setContentView(this,R.layout.activity_detail4,new MyComponent());    ...}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
完成后,这个ActivityDetail4Binding范围内的所有android:alpha="@{foo}"的方式赋值alpha的setter函数都会使用MyComponent#setAlpha。5.3 @BindingConversion有时候会遇到类型不匹配的问题,比如R.color.white是int,但是通过Data Binding赋值给android:background属性后,需要把int转换为ColorDrawable,实现方式如下:
* 1.定义一个静态函数,放在项目任意类中,@BindingConversionpublic static Drawable convertColorToDrawable(int drawable) {    return new ColorDrawable(drawable);}
[*]1
[*]2
[*]3
[*]4

[*]2.在layout.xml中使用Data Binding,如:
<Viewandroid:background="@{adapter.avatar != null ? @color/detail_background : @color/colorAccent }"android:layout_width="match_parent"android:layout_height="66dp">
[*]1
[*]2
[*]3
[*]4
对应在ActivityDetail4Binding.java中生成的代码如下所示,其中AvatarAdapterObjectn1为int类型:ViewBindingAdapter.setBackground(this.mboundView1, DetailActivity4.convertColorToDrawable(AvatarAdapterObjectn1));
[*]1
5.4 @BindingMethod例如layout.xml中android:onClick属性,在Binding中真正使用setter时,就对应到了setOnClickListener方法,@BindingMethod(type = View.class, attribute = "android:onClick", method = "setOnClickListener"),
[*]1
6 Data Binding利用编译器在背后做的那些事儿Data Binding相关的jar包由四部分组成,
* 1.baseLibrary-2.1.0-rc1.jar
作为运行时类库被打进APK中;
[*]2.DataBinderPlugin(gradle plugin)
在编译期使用,利用gradle-api(之前叫transform-api,1.5生,2.0改名)处理xml文件,生成DataBindingInfo.java;
[*]3.compiler-2.1.0-rc1.jar
在编译器使用,入口类继承自AbstractProcessor,用于处理注解,并生成Binding类,DataBindingCompoent.java,DataBinderMapper.java类;
[*]4.compilerCommon-2.1.0-rc1.jar
被DataBinderPlugin和compiler-2.1.0-rc1.jar所依赖
http://lib.csdn.net/article/android/34439

熊猫儿 发表于 2016-9-17 09:42

2.setter_store.bin,包含所有setter相关信息;
3.layoutinfo.bin,包含所有layout相关信息;
4.br.bin,包含所有BR相关信息;
以上bin文件都以Serializable方式序列化到磁盘上,需要的时候进行反序列化操作;
[*]绿色部分为最终产物,包括
1.data-binding-layout-out(最终输出到res/layout),即去掉根节点<layout>,去掉节点<data>,与不使用Data Binding时的layout相一致,例如data-binding-layout-out/activity_detail2.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent" android:tag="layout/activity_detail2_0" xmlns:android="http://schemas.android.com/apk/res/android">    <View      android:background="@color/detail_background"      android:layout_width="match_parent"      android:layout_height="66dp">    </View>    ...</LinearLayout>
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
2.DataBindingInfo.class,一个看似空的类,但在SOURCE阶段包含了一个@BindingBuildInfo注解,包含了基本DataBinding的基本信息,代码如下:// DataBindingInfo.classpublic class DataBindingInfo {    public DataBindingInfo() {    }}// @BindingBuildInfo@Target({ElementType.TYPE})@Retention(RetentionPolicy.SOURCE)public @interface BindingBuildInfo {    String buildId();    String modulePackage();    String sdkRoot();    int minSdk();    String layoutInfoDir();    String exportClassListTo();    boolean isLibrary();    boolean enableDebugLogs() default false;    boolean printEncodedError() default false;}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
3.DataBindingComponent.class,会根据自定义的DataBindingComponent自动生成对应实例化方法,例如:public interface DataBindingComponent {    MyComponent getMyComponent();}
[*]1
[*]2
[*]3
4.ViewDataBinding.class的子类(ActivityDetail2Binding.class等)
5.BR.class,Bindable属性索引表,例如:public class BR {    public static final int _all = 0;    public static final int adapter = 1;    public static final int name = 2;    public static final int visibility = 3;    public BR() {    }}

熊猫儿 发表于 2016-9-17 09:43

6.DataBindingMapper.class,Mapper,用于寻找某个layout.xml对应的ViewDataBinding类,例如:class DataBinderMapper {    static final int TARGET_MIN_SDK = 16;    public DataBinderMapper() {    }    public ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view, int layoutId) {      switch(layoutId) {      case 2130968602:            return ActivityDetail2Binding.bind(view, bindingComponent);      case 2130968603:            return ActivityDetail3Binding.bind(view, bindingComponent);       ....      default:            return null;      }    }    ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View[] views, int layoutId) {      return null;    }    int getLayoutId(String tag) {      if(tag == null) {            return 0;      } else {            int code = tag.hashCode();            switch(code) {            case -600937657:                if(tag.equals("layout/activity_detail2_0")) {                  return 2130968602;                }                break;            case -600936696:                if(tag.equals("layout/activity_detail3_0")) {                  return 2130968603;                }                break;            ....            return 0;      }    }    String convertBrIdToString(int id) {      return id >= 0 && id < DataBinderMapper.InnerBrLookup.sKeys.length?DataBinderMapper.InnerBrLookup.sKeys:null;    }    private static class InnerBrLookup {      static String[] sKeys = new String[]{"_all", "adapter", "name", "visibility"};      private InnerBrLookup() {      }    }}

熊猫儿 发表于 2016-9-17 09:44

6.2 相关编译流程
[*]STEP1 资源处理
aapt或者gradle执行时,都会触发资源处理,在资源处理过程中,DataBinding都会扫描一遍现有的资源,生成不包含<layout>的data-binding-layout-out以及DataBinding所需要的data-binding-info;
[*]STEP2 DataBindingInfo.class生成
在完成资源处理后,aapt或者gradle-api都会去执行DataBindingInfo.class生成操作,把相关的信息写入DataBindingInfo.class的@BindingBuildInfo注解中;
[*]STEP3 监听到注解变化
生成@BindingBuildInfo注解,或者code中发现有新的注解写入,AbstractProcessor注解处理器就开始执行注解处理。DataBinding中有一个ProcessDataBinding.java类专门来处理DataBinding相关的注解;
[*]STEP4 ProcessDataBinding处理注解,生成bin
ProcessDataBinding中处理注解永远会按顺执行3步,ProcessMethodAdapter,ProcessExpressions,ProcessBindable。每次执行都会从磁盘反序列化对应的bin文件,然后忘bin中写入新的,完成后再序列化到磁盘;
[*]STEP5 生成最终产物
执行ProcessMethodAdapter生成DataBindingComponents.class;执行ProcessExpressions生成ViewDataBinding.class子类(ActivityDetail2Binding.class),并触发DataBindingMapper.class更新;执行ProcessBindable生成BR.class,并触发DataBindingMapper.class更新;
7 细节补充-View Tag的使用第二章有讲到View是如何注入的,其实需要分两种情况:
* 1.如果这个View标签属性中只有id,没有其他”@{表达式}”形式,则按照第2章提到的方式直接通过id查找;
* 2.如果这个View标签属性中有”@{表达式}”形式的值,则编译器会自动给这个View加个android:tag=”binding_{N}”, 其中{N}按顺序从0开始递增,如android:tag=”binding_0”。当执行ViewDataBinding#mapBindings去注入View时,会找tag为binding_开头的View,随后执行View注入;另外,如果View标签原来就有android:tag值,则编译器会先保存原有值信息,写入android:tag=”binding_{N}”。当执行完view注入后,再把原来的值赋值给android:tag。注意如果原来的android:tag值为”binding_0”,那么在View注入时将会发生错乱。在完成View注入后,ActivityDetail3Binding会执行this.setRootTag(root),代码如下:public class ActivityDetail3Binding extends ViewDataBinding {    public ActivityDetail3Binding(DataBindingComponent bindingComponent, View root) {      super(bindingComponent, root, 0);      Object[] bindings = mapBindings(bindingComponent, root, 5, sIncludes, sViewsWithIds);      this.detailActionButton = (Button)bindings;      this.detailActionButton.setTag((Object)null);      ...      this.setRootTag(root);      this.invalidateAll();    }}
页: 21 22 23 24 25 26 27 28 29 30 [31] 32 33 34 35 36 37 38 39 40
查看完整版本: 【Android的一些重要知识6。。。。】