美文网首页
【原创】jetpack-LiveData实现双向绑定原理

【原创】jetpack-LiveData实现双向绑定原理

作者: seekting | 来源:发表于2020-08-17 01:23 被阅读0次

    jetpack-LiveData实现双向绑定原理

    重要的行代码

    mDbActivityBinding.lifecycleOwner = this

     override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            mDbActivityBinding = DataBindingUtil.setContentView(this, R.layout.db_activity)
            mDbActivityBinding.mdbViewModel =
                    ViewModelProviders.of(this).get(DBViewModel::class.java)
            mDbActivityBinding.lifecycleOwner = this
    
      @OnLifecycleEvent(Lifecycle.Event.ON_START)
            public void onStart() {
                ViewDataBinding dataBinding = mBinding.get();
                if (dataBinding != null) {
                    dataBinding.executePendingBindings();
                }
            }
    

    ViewDataBinding.executeBindingsInternal

     private void executeBindingsInternal() {
            if (mIsExecutingPendingBindings) {
                requestRebind();
                return;
            }
            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) {
                executeBindings();
                if (mRebindCallbacks != null) {
                    mRebindCallbacks.notifyCallbacks(this, REBOUND, null);
                }
            }
            mIsExecutingPendingBindings = false;
        }
    
    

    executeBindings(),这里有注册监听(如果没注册)和把数据绑定到TextView

     @Override
        protected void executeBindings() {
            long dirtyFlags = 0;
            synchronized(this) {
                dirtyFlags = mDirtyFlags;
                mDirtyFlags = 0;
            }
            java.lang.String mDBViewModelUserLastName = null;
            com.seekting.demo2019.jetpack.DBViewModel mDBViewModel = mMDBViewModel;
            com.seekting.demo2019.jetpack.User mDBViewModelUserGetValue = null;
            java.lang.String mDBViewModelUserFirstName = null;
            java.lang.String mDBViewModelPwd = null;
            androidx.lifecycle.MutableLiveData<com.seekting.demo2019.jetpack.User> mDBViewModelUser = null;
            androidx.databinding.ObservableField<java.lang.String> mDBViewModelUserFullName = null;
            java.lang.String mDBViewModelUserFullNameGet = null;
    
            if ((dirtyFlags & 0x17L) != 0) {
    
    
                if ((dirtyFlags & 0x14L) != 0) {
    
                        if (mDBViewModel != null) {
                            // read mDBViewModel.pwd
                            mDBViewModelPwd = mDBViewModel.getPwd();
                        }
                }
    
                    if (mDBViewModel != null) {
                        // read mDBViewModel.user
                        mDBViewModelUser = mDBViewModel.getUser();
                    }
                    updateLiveDataRegistration(0, mDBViewModelUser);
    
    
                    if (mDBViewModelUser != null) {
                        // read mDBViewModel.user.getValue()
                        mDBViewModelUserGetValue = mDBViewModelUser.getValue();
                    }
    
                if ((dirtyFlags & 0x15L) != 0) {
    
                        if (mDBViewModelUserGetValue != null) {
                            // read mDBViewModel.user.getValue().lastName
                            mDBViewModelUserLastName = mDBViewModelUserGetValue.getLastName();
                            // read mDBViewModel.user.getValue().firstName
                            mDBViewModelUserFirstName = mDBViewModelUserGetValue.getFirstName();
                        }
                }
    
                    if (mDBViewModelUserGetValue != null) {
                        // read mDBViewModel.user.getValue().fullName
                        mDBViewModelUserFullName = mDBViewModelUserGetValue.getFullName();
                    }
                    updateRegistration(1, mDBViewModelUserFullName);
    
    
                    if (mDBViewModelUserFullName != null) {
                        // read mDBViewModel.user.getValue().fullName.get()
                        mDBViewModelUserFullNameGet = mDBViewModelUserFullName.get();
                    }
            }
            // batch finished
            if ((dirtyFlags & 0x15L) != 0) {
                // api target 1
    
                androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView1, mDBViewModelUserFirstName);
                androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView2, mDBViewModelUserLastName);
            }
            if ((dirtyFlags & 0x10L) != 0) {
                // api target 1
    
                androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView1, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView1androidTextAttrChanged);
                androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView2, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView2androidTextAttrChanged);
                androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView3, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView3androidTextAttrChanged);
                androidx.databinding.adapters.TextViewBindingAdapter.setTextWatcher(this.mboundView4, (androidx.databinding.adapters.TextViewBindingAdapter.BeforeTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.OnTextChanged)null, (androidx.databinding.adapters.TextViewBindingAdapter.AfterTextChanged)null, mboundView4androidTextAttrChanged);
                this.mboundView5.setOnClickListener(mCallback1);
            }
            if ((dirtyFlags & 0x17L) != 0) {
                // api target 1
    
                androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView3, mDBViewModelUserFullNameGet);
            }
            if ((dirtyFlags & 0x14L) != 0) {
                // api target 1
    
                androidx.databinding.adapters.TextViewBindingAdapter.setText(this.mboundView4, mDBViewModelPwd);
            }
        }
    

    updateLiveDataRegistration会调registerTo

     protected void registerTo(int localFieldId, Object observable,
                CreateWeakListener listenerCreator) {
            if (observable == null) {
                return;
            }
            WeakListener listener = mLocalFieldObservers[localFieldId];
            if (listener == null) {
                listener = listenerCreator.create(this, localFieldId);
                mLocalFieldObservers[localFieldId] = listener;
                if (mLifecycleOwner != null) {
                    listener.setLifecycleOwner(mLifecycleOwner);
                }
            }
            listener.setTarget(observable);
        }
    

    listener.setTarget(observable) 第i个成员变量监听了livedata的变化

    public void setTarget(T object) {
        unregister();
        mTarget = object;
        if (mTarget != null) {
            "mObservable就是LiveData"
            mObservable.addListener(mTarget);
        }
    }
    

    当setValue被调用

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
    

    considerNotify

    @SuppressWarnings("unchecked")
    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
    
    @Override
    public void onChanged(@Nullable Object o) {
        ViewDataBinding binder = mListener.getBinder();
        if (binder != null) {
            binder.handleFieldChange(mListener.mLocalFieldId, mListener.getTarget(), 0);
        }
    }
    
    private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
        if (mInLiveDataRegisterObserver) {
            // We're in LiveData 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;
        }
        boolean result = onFieldChange(mLocalFieldId, object, fieldId);
        if (result) {
            requestRebind();
        }
    }
    

    请求重新绑定

    protected void requestRebind() {
        if (mContainingBinding != null) {
            mContainingBinding.requestRebind();
        } else {
            final LifecycleOwner owner = this.mLifecycleOwner;
            if (owner != null) {
                Lifecycle.State state = owner.getLifecycle().getCurrentState();
                if (!state.isAtLeast(Lifecycle.State.STARTED)) {
                    return; // wait until lifecycle owner is started
                }
            }
            synchronized (this) {
                if (mPendingRebind) {
                    return;
                }
                mPendingRebind = true;
            }
            if (USE_CHOREOGRAPHER) {
                mChoreographer.postFrameCallback(mFrameCallback);
            } else {
                mUIThreadHandler.post(mRebindRunnable);
            }
        }
    }
    
    @Override
    public void run() {
        synchronized (this) {
            mPendingRebind = false;
        }
        processReferenceQueue();
    
        if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
            // Nested so that we don't get a lint warning in IntelliJ
            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;
            }
        }
        executePendingBindings();
    }
    
    

    又回到了executePendingBindings,它负责注册监听(如果没监听 )和数据绑定到TextView

    相关文章

      网友评论

          本文标题:【原创】jetpack-LiveData实现双向绑定原理

          本文链接:https://www.haomeiwen.com/subject/yskfjktx.html