Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的DataBinding原理介紹

Android的DataBinding原理介紹

編輯:關於Android編程

Activity在inflate layout時,通過DataBindingUtil來生成綁定,從代碼看,是遍歷contentView得到View數組對象,然後通過數據綁定library生成對應的Binding類,含Views、變量、listeners等。生成類位於
build/intermediates/classes/debug/…package…/databinding/xxx.Java下,具體如何生成這裡暫不作深入。

綁定過程

首先,會在父類(ViewDataBinding)中實例化回調或Handler,用於之後的綁定操作;
private static final boolean USE_CHOREOGRAPHER = SDK_INT >= 16;

if (USE_CHOREOGRAPHER) {
  mChoreographer = Choreographer.getInstance();
  mFrameCallback = new Choreographer.FrameCallback() {
    @Override
    public void doFrame(long frameTimeNanos) {
      mRebindRunnable.run();
    }
  };
} else {
  mFrameCallback = null;
  mUIThreadHandler = new Handler(Looper.myLooper());
}
接著,通過調用 mapBindings(…) 遍歷布局以獲得包含bound、includes、ID Views的數組對象,再依次賦給對應View
final Object[] bindings = mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds);
this.mboundView0 = (Android" target="_blank">Android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
然後,調用 invalidateAll() -> requestRebind() -> … -> mRebindRunnable.run() – 執行 Runnable
// 用於動態重新綁定 Views
private final Runnable mRebindRunnable = new Runnable() {
  @Override
  public void run() {
    synchronized (this) {
      mPendingRebind = false;
    }
    .....
    executePendingBindings();
  }
};
最後,通過該Runnable會執行到 executePendingBindings() -> … -> executeBindings(),在這裡會執行綁定相關操作。
@Override
protected void executeBindings() {
  long dirtyFlags = 0;
  synchronized(this) {
    dirtyFlags = mDirtyFlags;  // mDirtyFlags 變量更新的標志
    mDirtyFlags = 0;
  }
  .....
}

設置變量(數據對象)

普通Javabean 對象

首先,通過mDirtyFlags標識變量(所有變量共用)
synchronized(this) {
  mDirtyFlags |= 0x1L;
}
然後,調用 notifyPropertyChanged(…) 來通知更新(若有回調)
public void notifyPropertyChanged(int fieldId) {
  if (mCallbacks != null) {
    mCallbacks.notifyCallbacks(this, fieldId, null);
  }
}
最後,調用 requestRebind() -> … -> executeBindings() 再次執行綁定操作,將數據更新到Views上
@Override
protected void executeBindings() {
  long dirtyFlags = 0;
  synchronized(this) {
    dirtyFlags = mDirtyFlags;
    mDirtyFlags = 0;
  }
  .....
}

Observable 對象

在設置變量時,會先調用 updateRegistration(..) 注冊一個Observable對象的監聽
public void setContact(com.connorlin.databinding.model.ObservableContact contact) {
  updateRegistration(0, contact);
  this.mContact = contact;
  synchronized(this) {
    mDirtyFlags |= 0x1L;
  }
  notifyPropertyChanged(BR.contact);
  super.requestRebind();
}
其他步驟同普通Javabean 對象

ObservableFields 對象

前期步驟同普通JavaBean 對象
與 Observable 對象不同的是,Observable對象的監聽是在 executeBindings() 中注冊的
@Override
protected void executeBindings() {
  long dirtyFlags = 0;
  synchronized(this) {
    dirtyFlags = mDirtyFlags;
    mDirtyFlags = 0;
  }
  ...
  if ((dirtyFlags & 0xfL) != 0) {
    if ((dirtyFlags & 0xdL) != 0) {
      if (contact != null) {
        // read contact.mName
        mNameContact = contact.mName;
      }
      updateRegistration(0, mNameContact);

      if (mNameContact != null) {
        // read contact.mName.get()
        mNameContact1 = mNameContact.get();
      }
    }
    ...
  }
  ...
}

注冊Observable對象監聽

入口 updateRegistration(0, contact) :
protected boolean updateRegistration(int localFieldId, Observable observable) {
  return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

private boolean updateRegistration(int localFieldId, Object observable,
    CreateWeakListener listenerCreator) {
  ...
  // 確保不重復監聽,先移除再添加觀察監聽
  unregisterFrom(localFieldId);
  registerTo(localFieldId, observable, listenerCreator);
  return true;
}

protected void registerTo(int localFieldId, Object observable,
    CreateWeakListener listenerCreator) {
  if (observable == null) {
    return;
  }

  // 創建對象監聽並存到mLocalFieldObservers中
  WeakListener listener = mLocalFieldObservers[localFieldId];
  if (listener == null) {
    // CREATE_PROPERTY_LISTENER -> create(...)
    listener = listenerCreator.create(this, localFieldId);
    mLocalFieldObservers[localFieldId] = listener;
  }

  // 將監聽綁定到Observable對象上
  listener.setTarget(observable);
}

每個Observable對象都會添加一個觀察監聽,保存在數組 mLocalFieldObservers 中,並以 localFieldId 索引。

CREATE_PROPERTY_LISTENER 為何物?
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
  @Override
  public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
    // 返回從WeakPropertyListener實例中獲取的監聽器(WeakListener)
    return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
  }
}

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
    implements ObservableReference {
  final WeakListener mListener;

  public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
    mListener = new WeakListener(binder, localFieldId, this);
  }

  @Override
  public WeakListener getListener() {
    return mListener;
  }

  @Override
  public void addListener(Observable target) {
    // WeakPropertyListener 繼承於 Observable.OnPropertyChangedCallback,
    // 所以 this 其實就是 Observable對象的屬性監聽器
    target.addOnPropertyChangedCallback(this);
  }

  ...
}

private static class WeakListener extends WeakReference {
  private final ObservableReference mObservable;
  protected final int mLocalFieldId;
  private T mTarget;

  ...

  public void setTarget(T object) {
    unregister();
    mTarget = object;
    if (mTarget != null) {
      // mObservable 是上面的 WeakPropertyListener對象
      // mTarget 是綁定到listener上得Observable對象
      mObservable.addListener(mTarget);
    }
  }

  ...
}

CREATE_PROPERTY_LISTENER 實際上只是一個接口實例,注冊時會調用它的create()方法創建一個弱引用listener,它的作用是將listener綁定到Observable對象上,
綁定時,會調用 listener.setTarget(…) 將Observable對象傳給 WeakPropertyListener實例,然後,WeakPropertyListener 會為 Observable對象添加OnPropertyChangedCallback。

addOnPropertyChangedCallback實現

addOnPropertyChangedCallback 在 BaseObservable中實現,首先會實例化一個PropertyChangeRegistry對象,同時創建一個用來通知Observable對象重新綁定更新的回調CallbackRegistry.NotifierCallback。然後將 OnPropertyChangedCallback 添加到PropertyChangeRegistry的回調列表中

@Override
public synchronized void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
  if (mCallbacks == null) {
    mCallbacks = new PropertyChangeRegistry();
  }
  mCallbacks.add(callback);
}

這樣,注冊Observable對象的監聽就完畢了。

更新(重新綁定)Observable對象

設置或更新Observable對象時都會調用notifyPropertyChanged()或notifyChange()來通知更新,那到底是如何更新的呢?

回調過程
public void notifyPropertyChanged(int fieldId) {
  // mCallbacks 是 PropertyChangeRegistry對象,在 addOnPropertyChangedCallback 時實例化
  // 如果注冊了Observable對象監聽,那麼mCallbacks不為null
  if (mCallbacks != null) {
    mCallbacks.notifyCallbacks(this, fieldId, null);
  }
}

// baseLibrary
private void notifyCallbacks(T sender, int arg, A arg2, int startIndex, int endIndex, long bits) {
  long bitMask = 1L;
  for(int i = startIndex; i < endIndex; ++i) {
    if((bits & bitMask) == 0L) {
      // mNotifier 是實例化PropertyChangeRegistry時創建的
      // mNotifier 即 CallbackRegistry.NotifierCallback
      this.mNotifier.onNotifyCallback(this.mCallbacks.get(i), sender, arg, arg2);
    }
    bitMask <<= 1;
  }
}

// PropertyChangeRegistry.NOTIFIER_CALLBACK
public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
    int arg, Void notUsed) {
  // callback 是為Observable對象添加的OnPropertyChangedCallback,即WeakPropertyListener
  callback.onPropertyChanged(sender, arg);
}

// WeakPropertyListener
public void onPropertyChanged(Observable sender, int propertyId) {
  // binder 即生成的Binding類對象
  ViewDataBinding binder = mListener.getBinder();
  ...
  binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}

private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
  // onFieldChange 實現在生成的Binding類中
  boolean result = onFieldChange(mLocalFieldId, object, fieldId);
  if (result) {
    // 如果對象屬性變化,將重新綁定
    requestRebind();
  }
}

通過 notifyPropertyChanged 調用到 mNotifier 回調, mNotifier 通知OnPropertyChangedCallback Observable對象屬性發生變化,然後在onPropertyChanged中又轉給ViewDataBinding對象(生成的Binding類)處理。

判斷是否需要重新綁定並執行,在生成的Binding類中實現
// 生成的Binding類中得方法
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
  // 如果變量不是Observable類型或沒有添加 Bindable注解,就不會判斷,直接返回false
  switch (localFieldId) {
    case 0 :
      return onChangeContact((com.connorlin.databinding.model.ObservableContact) object, fieldId);
  }
  return false;
}

private boolean onChangeContact(com.connorlin.databinding.model.ObservableContact contact, int fieldId) {
  switch (fieldId) {
    case BR.name: {
      synchronized(this) {
          mDirtyFlags |= 0x4L;// 通過mDirtyFlags判斷對象是否變化
      }
      return true;
    }
    ...
  }
  return false;
}

至此,更新過程完畢。

整個注冊與更新過程可以用一張流程圖來概括:

Android Data Binding 系列(二) -- Binding與Observer實現原理

事件處理

事件處理的原理很簡單,在生成Binding類中會實現View事件的監聽,在構造時實例化View的事件監聽,然後在綁定時將事件監聽對象賦值給對應View,這樣,點擊時就會觸發相應的監聽。

這裡以DataBindingDemo中 EventActivity部分為例:

生成的Binding類並實現View的事件監聽
public class ActivityEventBinding extends Android.databinding.ViewDataBinding
  implements Android.databinding.generated.callback.OnCheckedChangeListener.Listener,
    Android.databinding.generated.callback.OnClickListener.Listener {
  // Checkbox check監聽
  private final Android.widget.CompoundButton.OnCheckedChangeListener mCallback3;
  private final Android.view.View.OnClickListener mCallback2;
  private final Android.view.View.OnClickListener mCallback1;
  // listeners
  private OnClickListenerImpl mAndroidViewViewOnCl;
  ...
  // Listener Stub Implementations
  public static class OnClickListenerImpl implements Android.view.View.OnClickListener{
    private com.connorlin.databinding.handler.EventHandler value;
    public OnClickListenerImpl setValue(com.connorlin.databinding.handler.EventHandler value) {
      this.value = value;
      return value == null ? null : this;
    }
    @Override
    public void onClick(Android.view.View arg0) {
      this.value.onClickFriend(arg0);
    }
  }
  ...
}
實例化View的事件監聽
public ActivityEventBinding(Android.databinding.DataBindingComponent bindingComponent, View root) {
  super(bindingComponent, root, 0);
  ...
  // listeners
  mCallback3 = new Android.databinding.generated.callback.OnCheckedChangeListener(this, 3);
  mCallback2 = new Android.databinding.generated.callback.OnClickListener(this, 2);
  mCallback1 = new Android.databinding.generated.callback.OnClickListener(this, 1);
  invalidateAll();
}
在執行綁定中綁定View事件監聽
@Override
protected void executeBindings() {
  ...
  if ((dirtyFlags & 0x6L) != 0) {
    if (handler != null) {
      // read handler::onClickFriend
      AndroidViewViewOnCli = (((mAndroidViewViewOnCl == null)
        ? (mAndroidViewViewOnCl = new OnClickListenerImpl()) : mAndroidViewViewOnCl).setValue(handler));
    }
  }
  // batch finished
  if ((dirtyFlags & 0x6L) != 0) {
    this.mboundView1.setOnClickListener(AndroidViewViewOnCli);
  }
  if ((dirtyFlags & 0x4L) != 0) {
    this.mboundView2.setOnClickListener(mCallback1);
    this.mboundView3.setOnClickListener(mCallback2);
    Android.databinding.adapters.CompoundButtonBindingAdapter.setListeners(
      this.mboundView4, mCallback3, (Android.databinding.InverseBindingListener)null);
  }
}
觸發事件並執行

ViewStub

原理類似,只是利用 ViewStubProxy 來延遲綁定。

使用layout中的ViewStub實例化一個ViewStubProxy對象賦給viewstub變量,並與Bingding關聯
public ActivityViewStubBinding(Android.databinding.DataBindingComponent bindingComponent, View root) {
  super(bindingComponent, root, 0);
  final Object[] bindings = mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds);
  ...
  this.viewStub = new Android.databinding.ViewStubProxy((Android.view.ViewStub) bindings[1]);
  this.viewStub.setContainingBinding(this);
  ...
}
實例化ViewStubProxy的同時會注冊inflate監聽
private OnInflateListener mProxyListener = new OnInflateListener() {
  @Override
  public void onInflate(ViewStub stub, View inflated) {
    mRoot = inflated;
    mViewDataBinding = DataBindingUtil.bind(mContainingBinding.mBindingComponent,
        inflated, stub.getLayoutResource());
    mViewStub = null;

    if (mOnInflateListener != null) {
      mOnInflateListener.onInflate(stub, inflated);
      mOnInflateListener = null;
    }
    mContainingBinding.invalidateAll();
    mContainingBinding.forceExecuteBindings();
  }
};

public ViewStubProxy(ViewStub viewStub) {
  mViewStub = viewStub;
  mViewStub.setOnInflateListener(mProxyListener);
}
inflate ViewStub
if (!mActivityViewStubBinding.viewStub.isInflated()) {
  mActivityViewStubBinding.viewStub.getViewStub().inflate();
}

當ViewStub infate時,執行mProxyListener,其中會生成ViewStub的Binding,並強制執行主Binding重綁

綁定ViewStub
@Override
protected void executeBindings() {
  long dirtyFlags = 0;
  synchronized(this) {
    dirtyFlags = mDirtyFlags;
    mDirtyFlags = 0;
  }
  // batch finished
  if (viewStub.getBinding() != null) {
    viewStub.getBinding().executePendingBindings();
  }
}

這樣,ViewStub綁定就結束了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved