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

上篇文章 Android Data Binding 系列(一) – 詳細介紹與使用 介紹了 Data Binding 的基礎及其用法,本文接上篇,結合DataBindingDemo 來學習下 Data Binding 的實現。

綁定實現

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());
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 接着,通過調用 mapBindings(...) 遍歷佈局以獲得包含bound、includes、ID Views的數組對象,再依次賦給對應View
final Object[] bindings = mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds);
this.mboundView0 = (android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
  • 1
  • 2
  • 3
  • 然後,調用 invalidateAll() -> requestRebind() -> ... -> mRebindRunnable.run() - 執行 Runnable
// 用於動態重新綁定 Views
private final Runnable mRebindRunnable = new Runnable() {
    @Override
    public void run() {
        synchronized (this) {
            mPendingRebind = false;
        }
        .....
        executePendingBindings();
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 最後,通過該Runnable會執行到 executePendingBindings() -> ... -> executeBindings(),在這裏會執行綁定相關操作。
@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;   // mDirtyFlags 變量更新的標誌
        mDirtyFlags = 0;
    }
    .....
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

設置變量(數據對象)

普通 Java bean 對象

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

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 其他步驟同普通 Java bean 對象

ObservableFields 對象

  • 前期步驟同普通 Java Bean 對象

  • 與 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();
            }
        }
        ...
    }
    ...
}
  • 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

註冊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);
}
  • 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
  • 26
  • 27
  • 28
  • 29
  • 30

每個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<Observable> {
    final WeakListener<Observable> mListener;

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

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

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

    ...
}

private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
    private final ObservableReference<T> 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);
        }
    }

    ...
}
  • 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
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

這樣,註冊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();
    }
}
  • 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
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

通過 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

至此,更新過程完畢。

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

事件處理

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

這裏以 DataBindingDemoEventActivity部分爲例:

  • 生成的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);
        }
    }
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 實例化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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 在執行綁定中綁定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);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 觸發事件並執行

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);
    ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 實例化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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • inflate ViewStub
if (!mActivityViewStubBinding.viewStub.isInflated()) {
    mActivityViewStubBinding.viewStub.getViewStub().inflate();
}
  • 1
  • 2
  • 3

當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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

這樣,ViewStub綁定就結束了。

本篇完,敬請期待下篇…


我的簡書賬號是 ConnorLin,歡迎關注!

我的簡書專題是 Android開發技術分享,歡迎關注!

我的個人博客 歡迎關注!

原創文章,歡迎轉載,轉載請註明出處!

歡迎您掃一掃上面的微信公衆號,訂閱我的博客!

轉自: https://blog.csdn.net/zhixuan322145/article/details/51897272
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章