Android DataBinding單向數(shù)據(jù)綁定深入探究
在前面DataBinding原理----布局的加載這篇文章中,我們說(shuō)明了DataBinding中布局的加載過(guò)程,這里繼續(xù)下一步,數(shù)據(jù)是如何進(jìn)行綁定的,這里只介紹單向數(shù)據(jù)綁定,即數(shù)據(jù)的變化會(huì)反映到控件上;后面再介紹雙向數(shù)據(jù)綁定。
在分析源碼之前,在心里要有一個(gè)概念就是這里的數(shù)據(jù)綁定是基于觀察者模式來(lái)實(shí)現(xiàn)的,所以在閱讀這部分源碼的時(shí)候要著重分清楚,誰(shuí)是觀察者誰(shuí)是被觀察者,把這個(gè)思想放在心理,這樣就能抓住代碼的本質(zhì)。
這一篇分為兩個(gè)小部分,首先是數(shù)據(jù)的綁定流程分析,然后是觀察者模式綁定關(guān)系的建立流程。
一、數(shù)據(jù)綁定流程
代碼分析,走起。還是貼一段Activity的代碼如下:
class MainActivity : AppCompatActivity() {
private val viewModel: SimpleViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.lifecycleOwner = this
binding.viewModel = viewModel
}
}數(shù)據(jù)綁定的關(guān)鍵就是binding.viewModel = viewModel這行代碼,其調(diào)用的方法實(shí)現(xiàn)如下:
public void setViewModel(@Nullable com.zfang.databindingstudy.module.SimpleViewModel ViewModel) {
this.mViewModel = ViewModel;
synchronized(this) {
mDirtyFlags |= 0x4L;
}
notifyPropertyChanged(BR.viewModel);
super.requestRebind();
}notifyPropertyChanged這一行其實(shí)就是在通知觀察者,數(shù)據(jù)發(fā)生變化了。不過(guò)這不是我們這里關(guān)注的重點(diǎn)(不過(guò)注意這里的mDirtyFlags 已經(jīng)被修改了,已經(jīng)有值)。重點(diǎn)在后面的那一行super.requestRebind(),其實(shí)現(xiàn)如下:
protected void requestRebind() {
//處理有include標(biāo)簽的情況
if (mContainingBinding != null) {
mContainingBinding.requestRebind();
} else {
//我們的場(chǎng)景下走的是這里
final LifecycleOwner owner = this.mLifecycleOwner;
if (owner != null) {
//如果生命周期不是至少STARTED則返回
Lifecycle.State state = owner.getLifecycle().getCurrentState();
if (!state.isAtLeast(Lifecycle.State.STARTED)) {
return; // wait until lifecycle owner is started
}
}
synchronized (this) {
if (mPendingRebind) {
return;
}
//置標(biāo)志位
mPendingRebind = true;
}
if (USE_CHOREOGRAPHER) {
//走這里,使用垂直同步刷新
mChoreographer.postFrameCallback(mFrameCallback);
} else {
mUIThreadHandler.post(mRebindRunnable);
}
}
}首先判斷是不是屬于include標(biāo)簽的情況(也就是布局中包含include標(biāo)簽),如果不是則走到else分支,然后判斷生命周期是不是至少STARTED狀態(tài),如果不是則不執(zhí)行數(shù)據(jù)綁定(生命周期恢復(fù)的時(shí)候會(huì)再執(zhí)行數(shù)據(jù)綁定);如果滿(mǎn)足生命周期要求,則繼續(xù)判斷,首先把mPendingRebind 置位(避免重復(fù)綁定數(shù)據(jù)),然后使用垂直同步刷新機(jī)制post了一個(gè)callback,callback實(shí)現(xiàn)(位于ViewDataBinding的構(gòu)建函數(shù)中)如下:
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());
}其實(shí)最終走的還是mRebindRunnable,其實(shí)現(xiàn)如下:
private final Runnable mRebindRunnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
mPendingRebind = false;
}
//處理弱引用隊(duì)列中的監(jiān)聽(tīng)器,避免內(nèi)在泄漏
processReferenceQueue();
//如果是Android4.4及以后走這里
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
// Nested so that we don't get a lint warning in IntelliJ
//如果View還沒(méi)attach上,則返回;后面attach上會(huì)再執(zhí)行數(shù)據(jù)綁定
if (!mRoot.isAttachedToWindow()) {
// Don't execute the pending bindings until the View
// is attached again.
mRoot.removeOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
mRoot.addOnAttachStateChangeListener(ROOT_REATTACHED_LISTENER);
return;
}
}
//執(zhí)行數(shù)據(jù)綁定.
executePendingBindings();
}
};嗯,代碼中都寫(xiě)了注釋。首先處理弱引用隊(duì)列,避免內(nèi)存泄漏,然后判斷如果View還沒(méi)attach則返回,后面attach上再執(zhí)行數(shù)據(jù)綁定。最后調(diào)用executePendingBindings,執(zhí)行數(shù)據(jù)綁定。
public void executePendingBindings() {
if (mContainingBinding == null) {
//沒(méi)有include會(huì)走這里
executeBindingsInternal();
} else {
mContainingBinding.executePendingBindings();
}
}我們的場(chǎng)景下走executeBindingsInternal,代碼如下:
private void executeBindingsInternal() {
if (mIsExecutingPendingBindings) {
requestRebind();
return;
}
//這里調(diào)用了apt代碼生存的方法,也就是我們工程中的方法。
if (!hasPendingBindings()) {
return;
}
mIsExecutingPendingBindings = true;
mRebindHalted = false;
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBIND, null);
// The onRebindListeners will change mPendingHalted
if (mRebindHalted) {
mRebindCallbacks.notifyCallbacks(this, HALTED, null);
}
}
if (!mRebindHalted) {
//這里執(zhí)行綁定
executeBindings();
if (mRebindCallbacks != null) {
mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
}
}
mIsExecutingPendingBindings = false;
}上面主要是一些條件判斷,避免重復(fù)執(zhí)行綁定。其中方法hasPendingBindings判斷有沒(méi)有需要執(zhí)行數(shù)據(jù)綁定,最后executeBindings調(diào)用執(zhí)行數(shù)據(jù)綁定;hasPendingBindings的實(shí)現(xiàn)位于ActivityMainBindingImpl.java中,也就是DataBinding幫我們生存的類(lèi),代碼如下:
//ActivityMainBindingImpl.java
public boolean hasPendingBindings() {
synchronized(this) {
if (mDirtyFlags != 0) {
return true;
}
}
return false;
}上面我們說(shuō)過(guò)mDirtyFlags 在setViewModel方法調(diào)用的時(shí)候參數(shù)已經(jīng)不為0了,所以這里會(huì)返回true,也就是后面會(huì)執(zhí)行到executeBindings方法,其實(shí)現(xiàn)也位于ActivityMainBindingImpl.java類(lèi)中,代碼如下:
@Override
protected void executeBindings() {
long dirtyFlags = 0;
synchronized (this) {
//復(fù)制位標(biāo)識(shí),記錄了哪些數(shù)據(jù)發(fā)生變化。
dirtyFlags = mDirtyFlags;
mDirtyFlags = 0;
}
java.lang.String viewModelFirstGetValue = null;
androidx.lifecycle.LiveData<java.lang.String> viewModelSecond = null;
androidx.lifecycle.LiveData<java.lang.String> viewModelFirst = null;
java.lang.String viewModelSecondGetValue = null;
com.zfang.databindingstudy.module.SimpleViewModel viewModel = mViewModel;
//根據(jù)dirtyFlags 判斷哪些數(shù)據(jù)發(fā)生變化,一個(gè)變量會(huì)對(duì)應(yīng)到二進(jìn)制里面的一個(gè)位
//該位不為0,說(shuō)明數(shù)據(jù)有變化,于是會(huì)執(zhí)行相應(yīng)的獲得數(shù)據(jù)邏輯。
if ((dirtyFlags & 0xfL) != 0) {
if ((dirtyFlags & 0xdL) != 0) {
if (viewModel != null) {
// read viewModel.second
viewModelSecond = viewModel.getSecond();
}
updateLiveDataRegistration(0, viewModelSecond);
if (viewModelSecond != null) {
// read viewModel.second.getValue()
viewModelSecondGetValue = viewModelSecond.getValue();
}
}
if ((dirtyFlags & 0xeL) != 0) {
if (viewModel != null) {
// read viewModel.first
viewModelFirst = viewModel.getFirst();
}
//建立觀察者綁定關(guān)系
updateLiveDataRegistration(1, viewModelFirst);
if (viewModelFirst != null) {
// read viewModel.first.getValue()
viewModelFirstGetValue = viewModelFirst.getValue();
}
}
}
// batch finished
//根據(jù)上面拿到的數(shù)據(jù)調(diào)用setText,也就是設(shè)置了相應(yīng)的數(shù)據(jù)到UI上,實(shí)現(xiàn)
//了數(shù)據(jù)的變化更新的UI邏輯。
if ((dirtyFlags & 0xeL) != 0) {
// api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.first, viewModelFirstGetValue);
}
if ((dirtyFlags & 0xdL) != 0) {
// api target 1
androidx.databinding.adapters.TextViewBindingAdapter.setText(this.second, viewModelSecondGetValue);
}
}
// Listener Stub Implementations
// callback impls
// dirty flag
private long mDirtyFlags = 0xffffffffffffffffL;
/* flag mapping
flag 0 (0x1L): viewModel.second
flag 1 (0x2L): viewModel.first
flag 2 (0x3L): viewModel
flag 3 (0x4L): null
flag mapping end*/
//end首先說(shuō)明下,我們的model里面一般來(lái)說(shuō)會(huì)有幾個(gè)變量,其實(shí)每一個(gè)變量在DataBinding中都會(huì)有一個(gè)二進(jìn)制位來(lái)標(biāo)識(shí)當(dāng)前數(shù)據(jù)是否發(fā)生了變化,如果發(fā)生變化,則該位置1,然后用dirtyFlags 作一個(gè)“與”運(yùn)算就可以判斷出該數(shù)據(jù)位是否發(fā)生了變化(好好體會(huì)下)。
對(duì)應(yīng)到我們的場(chǎng)景中,flag 0 (0x1L): viewModel.second這個(gè)標(biāo)識(shí)就對(duì)應(yīng)到second這個(gè)變量,而flag 1 (0x2L): viewModel.first就對(duì)應(yīng)到first這個(gè)變量,再用dirtyFlags作運(yùn)算就知道哪個(gè)位發(fā)生變化。
等等,數(shù)據(jù)是已經(jīng)綁定了,怎么沒(méi)看到觀察者模式的綁定關(guān)系?其實(shí)上面的代碼注釋已經(jīng)說(shuō)明了,這行代碼updateLiveDataRegistration正是建立了觀察者模式的綁定關(guān)系。
終于看到數(shù)據(jù)的綁定了,下面繼續(xù)看下updateLiveDataRegistration是如何建立觀察者模式的綁定關(guān)系。
二、建立觀察者模式綁定關(guān)系
首先貼上updateLiveDataRegistration的代碼如下:
//ViewDataBinding.java
protected boolean updateLiveDataRegistration(int localFieldId, LiveData<?> observable) {
mInLiveDataRegisterObserver = true;
try {
return updateRegistration(localFieldId, observable, CREATE_LIVE_DATA_LISTENER);
} finally {
mInLiveDataRegisterObserver = false;
}
}首先作下參數(shù)說(shuō)明,第一個(gè)參數(shù)說(shuō)明是哪個(gè)位置上的變量,第二個(gè)是個(gè)LiveData(對(duì)應(yīng)到了我們?cè)赩iewModel中定義的數(shù)據(jù)變量,也就是要被觀察的變量)。這里只是簡(jiǎn)單的轉(zhuǎn)發(fā)調(diào)用下updateRegistration,最后一個(gè)參數(shù)是一個(gè)creator(利用了工廠(chǎng)方法模式),其實(shí)現(xiàn)如下:
private static final CreateWeakListener CREATE_LIVE_DATA_LISTENER = new CreateWeakListener() {
@Override
public WeakListener create(
ViewDataBinding viewDataBinding,
int localFieldId,
ReferenceQueue<ViewDataBinding> referenceQueue
) {
return new LiveDataListener(viewDataBinding, localFieldId, referenceQueue)
.getListener();
}
};就是創(chuàng)建了一個(gè)LiveDataListener對(duì)象,并調(diào)用了它的getListener方法,該方法會(huì)返回一個(gè)WeakListener類(lèi)型的變量。繼續(xù)上面的updateRegistration方法,代碼如下:
protected boolean updateRegistration(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
//由于observable是一個(gè)livedata對(duì)象且不空,所以不會(huì)走這里。
if (observable == null) {
return unregisterFrom(localFieldId);
}
WeakListener listener = mLocalFieldObservers[localFieldId];
//因?yàn)槭堑谝淮芜M(jìn)入這里,所以會(huì)進(jìn)入到registerTo中
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;
}根據(jù)代碼中的注釋可知,如果是第一次進(jìn)入最后會(huì)進(jìn)入到registerTo方法中,其實(shí)現(xiàn)如下:
protected void registerTo(int localFieldId, Object observable,
CreateWeakListener listenerCreator) {
if (observable == null) {
return;
}
WeakListener listener = mLocalFieldObservers[localFieldId];
if (listener == null) {
//上面說(shuō)過(guò)這里返回的是個(gè)WeakListener對(duì)象。
listener = listenerCreator.create(this, localFieldId, sReferenceQueue);
//把對(duì)象保存起來(lái)
mLocalFieldObservers[localFieldId] = listener;
//設(shè)置lifeCycle
if (mLifecycleOwner != null) {
listener.setLifecycleOwner(mLifecycleOwner);
}
}
//建立觀察者綁定關(guān)系
listener.setTarget(observable);
}首先判斷如果listener則創(chuàng)建,返回的是一個(gè)WeakListener對(duì)象(其實(shí)中間還有一個(gè)LiveDataListener對(duì)象,WeakListener對(duì)象的mObservable變量會(huì)持有LiveDataListener對(duì)象),然后保存到mLocalFieldObservers數(shù)組中,看上去就是一個(gè)觀察者數(shù)組對(duì)象,最后調(diào)用WeakListener的setTarget方法,其實(shí)現(xiàn)如下:
public void setTarget(T object) {
//這里的object就是傳遞過(guò)來(lái)的liveData對(duì)象,下面會(huì)把它保存到target中
unregister();
mTarget = object;
if (mTarget != null) {
//mObservable其實(shí)就是LiveDataListener對(duì)象
mObservable.addListener(mTarget);
}
}重復(fù)下,上面的mTarget就是ViewModel中的LiveData對(duì)象,mObservable其實(shí)就是LiveDataListener對(duì)象,所以調(diào)用了LiveDataListener的addListener方法,實(shí)現(xiàn)如下:
//ViewDataBinding$LiveDataListener
public void addListener(LiveData<?> target) {
//target是LiveData
LifecycleOwner lifecycleOwner = getLifecycleOwner();
if (lifecycleOwner != null) {
//LiveData監(jiān)聽(tīng)了lifecycleOwner的生命周期變化。
target.observe(lifecycleOwner, this);
}
}很簡(jiǎn)單的邏輯,就是通過(guò)target.observe(lifecycleOwner, this)建立了觀察者模式的綁定關(guān)系。之后生命周期發(fā)生變化就會(huì)調(diào)用到onChange方法,代碼如下:
public void onChanged(@Nullable Object o) {
ViewDataBinding binder = mListener.getBinder();
if (binder != null) {
binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0);
}
}這里的binder其實(shí)就是ActivityMainBindingImpl,隨后調(diào)用handleFieldChange,代碼如下:
protected void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
if (mInLiveDataRegisterObserver || mInStateFlowRegisterObserver) {
// We're in LiveData or StateFlow registration, which always results in a field change
// that we can ignore. The value will be read immediately after anyway, so
// there is no need to be dirty.
return;
}
//調(diào)用了子類(lèi)實(shí)現(xiàn),也就是ActivityMainBindingImpl
boolean result = onFieldChange(mLocalFieldId, object, fieldId);
if (result) {
//重新綁定數(shù)據(jù)
requestRebind();
}
}首先調(diào)用了onFiledChange,它的實(shí)現(xiàn)位于apt生存的代碼中,如下:
@Override
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
switch (localFieldId) {
case 0 :
return onChangeViewModelSecond((androidx.lifecycle.LiveData<java.lang.String>) object, fieldId);
case 1 :
return onChangeViewModelFirst((androidx.lifecycle.LiveData<java.lang.String>) object, fieldId);
}
return false;
}
private boolean onChangeViewModelSecond(androidx.lifecycle.LiveData<java.lang.String> ViewModelSecond, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x1L;
}
return true;
}
return false;
}
private boolean onChangeViewModelFirst(androidx.lifecycle.LiveData<java.lang.String> ViewModelFirst, int fieldId) {
if (fieldId == BR._all) {
synchronized(this) {
mDirtyFlags |= 0x2L;
}
return true;
}
return false;
}根據(jù)哪些數(shù)據(jù)發(fā)生變化,返回true或者false,如果返回true,之后會(huì)調(diào)用requestRebind,不正是對(duì)應(yīng)開(kāi)了開(kāi)頭中分析的函數(shù)了嗎?形成閉環(huán)。從而完成了整個(gè)觀察者模式的建立與響應(yīng)流程。
這一篇中分析了數(shù)據(jù)的綁定與觀察者模式的建立流程,如果想了解DataBinding中布局的加載可以看前一篇DataBinding原理----布局的加載。下一篇將會(huì)分析雙向數(shù)據(jù)綁定流程。
到此這篇關(guān)于Android DataBinding單向數(shù)據(jù)綁定深入探究的文章就介紹到這了,更多相關(guān)Android DataBinding 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 淺析Android企業(yè)級(jí)開(kāi)發(fā)數(shù)據(jù)綁定技術(shù)
- Android Studio綁定下拉框數(shù)據(jù)詳解
- 詳解Android的MVVM框架 - 數(shù)據(jù)綁定
- Android Data Binding數(shù)據(jù)綁定詳解
- Android RecyclerView 數(shù)據(jù)綁定實(shí)例代碼
- Android ListView數(shù)據(jù)綁定顯示的三種解決方法
- Android中 自定義數(shù)據(jù)綁定適配器BaseAdapter的方法
- Android數(shù)據(jù)雙向綁定原理實(shí)現(xiàn)和應(yīng)用場(chǎng)景
相關(guān)文章
Android開(kāi)發(fā)從相機(jī)或相冊(cè)獲取圖片裁剪
當(dāng)我們需要上傳圖片時(shí),想要裁剪成我們需要的尺寸大小,android手機(jī)都帶有這個(gè)功能,很容易,那么此功能是如何實(shí)現(xiàn)的呢?下面小編給大家介紹Android開(kāi)發(fā)從相機(jī)或相冊(cè)獲取圖片裁剪,需要的朋友可以參考下2015-10-10
Android 簡(jiǎn)單的照相機(jī)程序的實(shí)例代碼
終于經(jīng)過(guò)多次找錯(cuò),修改把一個(gè)簡(jiǎn)單的照相機(jī)程序完成了,照相類(lèi)代碼如下:2013-05-05
Android實(shí)現(xiàn)音樂(lè)視頻播放
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)音樂(lè)視頻播放,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效
這篇文章主要為大家介紹了Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Android開(kāi)發(fā)中Bitmap高效加載使用詳解
在Android開(kāi)發(fā)中,我們經(jīng)常與Bitmap打交道,而對(duì)Bitmap的不恰當(dāng)?shù)牟僮鹘?jīng)常會(huì)導(dǎo)致OOM(Out of Memory)。這篇文章我們會(huì)介紹如何高效地在Android開(kāi)發(fā)中使用Bitmap,在保證圖片顯示質(zhì)量的前提下盡可能占用更小的內(nèi)存。2017-12-12
Android中二維碼的掃描和生成(使用zxing庫(kù))
ZXing是一個(gè)開(kāi)放源碼的,用Java實(shí)現(xiàn)的多種格式的1D/2D條碼圖像處理庫(kù),它包含了聯(lián)系到其他語(yǔ)言的端口,下面這篇文章主要給大家介紹了關(guān)于Android中二維碼掃描和生成的相關(guān)資料,主要使用的zxing庫(kù),需要的朋友可以參考下2022-09-09

