• An overview of the

    • This example points to DataBinding in Java, Kotlin two languages to start with the use of DataBinding operation mechanism; How is bidirectional binding implemented? Why can’t annotations be used in Kotlin? Where does DataBinding consume memory? The problems such as

Source code analysis: DataBinding_Java version

  • BR file in the Model layer: Integer tokens are added for each maintained field, with which data flows internally

    • Schematic: BR file source code

    • Schematic diagram: Integer tokens can be used instead when sending br. fields in the Model layer; Not recommended. Use the br. field to reduce fault tolerance

  • How does DataBinding do the View layer and Model hand in hand: act as an intermediary, acting as the VM layer

    • VM layer and View layer binding:

        final ActivityMainBinding binding = 
        DataBindingUtil.setContentView(this,R.layout.activity_main);
      Copy the code
    • The VM layer is bound to the Model layer

      JavaBean User User; // JavaBean User User; user = new User("wasbry","123456"); binding.setUser(user); // Create a binding relationship with DataBinding, otherwise there is no effectCopy the code

      User = new user (“wasbry”,”123456″); Default values are provided for the View layer

       android:text="@{user.name}"
       android:text="@{user.pwd}"
      Copy the code
  • Data-driven UI details:

    • After the VM layer establishes bidirectional binding

      • Data-driven UI: Only one thread needs to be opened for Model layer data modification –>UI update
      • UI modification data: Displays user input in the form of logs
    • Code display:

      //Model--->View new Thread(new Runnable() { @Override public void run() { for(int i = 0; i < 10; i++){ try { Thread.sleep(1000); User.setname (" + I +"); User.setpwd (" + I +"); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();Copy the code
  • Data Flow Order: Why is findViewById no longer needed

    1. Update fields in the VM layer

      User.setname (" + I +");Copy the code
    2. Jump to the Model layer

      notifyPropertyChanged(BR.name); // APT is also the main processor technology BR fileCopy the code
    3. Jump to the View layer

       android:text="@{user.name}"
      Copy the code
  • Layout split details:

    • Process analysis: DataBinding reads the layout given to it to manage, and finds the other half by using the tag attribute inside.

      • Activity_main.xml: Hand it over to DataBinding for management

        <? The XML version = "1.0" encoding = "utf-8"? > <! DataBinding manages the entire layout file, but splits it into two parts --> <! - to use within the DataBinding - > < layout XMLNS: android = "http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="user" type="com.wasbry.myapplication.User" /> </data> <! <LinearLayout Android :layout_width="match_parent" Android :layout_height="match_parent" Android :layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.name}" android:textSize="50sp" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{user.pwd}" android:textSize="50sp"/> </LinearLayout> </layout>Copy the code
      • Activity_main-layout. XML: DataBinding’s internal managed layout

        • Path: the build/intermediates/data_binding_layout_info_type_merge/debug/out/activity_main – layout. XML

        • Details: Use tags to get controls in the layout (the more complex the layout, the more complex the layout is to pull out to DataBinding to manage)

          <Targets> <Target tag="layout/activity_main_0" view="LinearLayout"> <Expressions /> <location endLine="35" endOffset="17" startLine="15" startOffset="3" /> </Target> <Target id="@+id/tv1" tag="binding_1" view="TextView"> <Expressions> <Expression attribute="android:text" text="user.name"> <Location endLine="24" endOffset="38" startLine="24" startOffset="12" /> <TwoWay>false</TwoWay> <ValueLocation endLine="24" endOffset="36" startLine="24" startOffset="28" /> </Expression> </Expressions> <location endLine="26" endOffset="13" startLine="20" startOffset="8" />  </Target> <Target id="@+id/tv2" tag="binding_2" view="TextView"> <Expressions> <Expression attribute="android:text" text="user.pwd"> <Location endLine="32" endOffset="37" startLine="32" startOffset="12" /> <TwoWay>false</TwoWay> <ValueLocation endLine="32" endOffset="35" startLine="32" startOffset="28" /> </Expression> </Expressions> <location endLine="33" endOffset="36" startLine="28" startOffset="8" /> </Target> </Targets>Copy the code
      • Activity_main. XML: Split the original layout and hand it to Android to draw UI

        • Path: the build/intermediates/incremental/mergeDebugResources/stripped dir/layout/activity_main XML

        • Details: Added a tag to each control, matching the tag properties that were removed from the layout and handed over to DataBinding to manage

          The < TextView... Android: tag = "binding_1" / > < TextView... android:tag="binding_2" />Copy the code
  • Why should setContentView be discarded

    • Use ActivityMainBinding to refer to the layout file:

       final ActivityMainBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
      Copy the code
      • Proof refers to: click on it (CTRL+H left mouse button), found directly will draw the layout file automatically selected

    • Discard the setContentView statement

       //        setContentView(R.layout.activity_main);
      Copy the code
      • It’s actually called internally



    • SetContentView analysis: Call bindToAddedViews

      public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity, int layoutId, @nullable DataBindingComponent bindingComponent) {// load layout activity.setcontentview (layoutId) based on the layoutId; DecorView = activity.getwindow ().getDecorView(); ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content); Return bindToAddedViews(bindingComponent, contentView, 0, layoutId); }Copy the code
    • BindToAddedViews:

      • Bind is called no matter how many child views there are

         //一个孩子
         return bind(component, childView, layoutId);
         //多个孩子
         return bind(component, children, layoutId);
        Copy the code
    • The bind analysis

      • Pass in layout information: DataBindingComponent bindingComponent, View root,int layoutId

      • Call: getDataBinder

         return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);
        Copy the code
    • GetDataBinder: Abstract function

       public abstract ViewDataBinding getDataBinder(DataBindingComponent bindingComponent, View view,
                   int layoutId);
      Copy the code
      • Click the green interface symbol on the left and select the first one to jump to

        • Schematic diagram:

        • The source code is not complete and needs to be downloaded (this will not be successful because it is an ARR that contains the JAR package).

        • Because the source code is not complete, so no longer analyze this code, need to jump:

          • Path: package androidx. Databinding. If baseAdapters;
          • File name: databinderMapPerimpl.class
        • Need to jump to file with the same name: incomplete source code

          • Because aar package code will have a APT code in build/generated/ap_generated_sources/debug/out
          • Path: the build/generated/ap_generated_sources/debug/out/com/wasbry/myapplication/DataBinderMapperImpl Java
          • File name: databindermapPerimpl.java
        • So the abstract function is called databinderMapPerimp.java after the jump

    • DataBinderMapperImpl. Java is analyzed

      • The first step is to get the layout of the tag (the original layout is stripped out for the Android Draw View) : to get all the controls inside

        case LAYOUT_ACTIVITYMAIN: {if ("layout/activity_main_0". Equals (tag)) {return new ActivityMainBindingImpl(Component, view); }Copy the code
  • ActivityMainBindingImpl analysis

    • Constructor 1: Drill down to an array of objects

      • Why 3, because it has a tag of 3 controls,10 controls is 10
       public ActivityMainBindingImpl(@Nullable androidx.databinding.DataBindingComponent bindingComponent, @NonNull View root) {
           this(bindingComponent, root, mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds));
       }
      Copy the code
    • Constructor two: Triggers a static code block

      • ActivityMainBindingImpl will inherit from ViewDataBinding, just not see it
      private ActivityMainBindingImpl(androidx.databinding.DataBindingComponent bindingComponent, View root, Object[] Bindings (Bindings) {// This is super super(bindingComponent, root, 2, (Android.Widget.editText) Bindings [1], (android.widget.EditText) bindings[2] );Copy the code
    • MapBindings analysis: Packaging all controls in a layout into an array of objects (a control is an object), resulting in memory consumption

      • It’s actually slower than findViewById

         protected static Object[] mapBindings
        Copy the code
      • Find the root layout.

    • Static code block (the second one is very memory consuming, Model– >View data-driven UI) : added listener for each control, very memory consuming

      static { if (VERSION.SDK_INT < VERSION_CODES.KITKAT) { ROOT_REATTACHED_LISTENER = null; } else {/ / for each control added listening, very memory ROOT_REATTACHED_LISTENER = new OnAttachStateChangeListener () {Copy the code
      • Eventually it starts the thread, keeps calling back, and finally gets the tag control, and calls setText, which is a real time listener
      • Call excute, call it back, and find setText
    • The third point consumes memory (View– >Model)

      • In XML: this equals sign

        The < EditText... android:text="@={user.nameF}" />Copy the code
      • Produces a textWatcher listener, one for each control, which is distinguished by the control’s tag

  • Why does the View trigger the Model and the Model trigger the View without an infinite loop?

    • Inside user.setName(java.lang.string) : this event is consumed, similar to the chain of responsibility pattern
    • Because it is APT technology, it will generate code dynamically
  • The core of the DataBinding

    • Use APT technology, scan layout files, generated two layout files;

DataBinding implements data-driven UI(Kotlin version)

  • Why can’t the @bindable annotation be used in the Model layer

    1. Annotations are intended for use by methods or fields

    2. Each field in Kotlin has a default get/set method, and you can override the get/set method for the field

      var name : String ? = null get() { return field } set(value : String ?) { field = value }Copy the code
    3. But the rewritten get/set method is just an expression that doesn’t work at all

  • Kotlin works with DataBInding on how to maintain Model layer data

    • ObservableField+ generics + lazy loading

    • Code:

      Class User{// BaseObservable() is invalid. This works in Java, but not in Kotlin. Val nameF: ObservableField<String> by lazy { ObservableField<String>() } val pwdF : ObservableField<String> by lazy { ObservableField<String>() } }Copy the code
  • How is bidirectional binding set up in Kotlin?

    • Model – > View:

      Private val user = user () val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main) binding.user = userCopy the code
    • View– >Model: Note that two-way binding must be equal sign

      / / XML < EditText... Android: text = "@ = {user. NameF}" / > < EditText... Android: text = "@ = {user. PwdF}" / > / / VM layer in the d (" MainActivity ", "user input the first field is ${user. NameF. The get ()}," ${user.pwdf.get ()}Copy the code

      The so-called data-driven UI, UI drives data; You are simply manipulating the Model layer data tied to the DataBinding