안드로이드 MVVM의 LiveData 소스코드 연구

        Android에서 공식적으로 제공하는 MVVM 패턴은 DataBinding, ViewModel 및 LiveData로 구성됩니다.

        더 이상 고민하지 않고 LiveData가 어떻게 사용되는지 봅시다.

class TestActivity : AppCompatActivity() {

    private var data: MutableLiveData<String> = MutableLiveData()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)

        // 通过 observe LiveData 数据
        data.observe(this, object : Observer<String> {

            // 通过 observe 回调 数据
            override fun onChanged(t: String?) {
                Timber.tag("MyTest").d(t)
            }

        })
        
        button.setOnClickListener {
            /**
             * 通过 postValue / setValue 设置数据
             * setValue() 必须在主线程
             * postValue() 在哪个线程设置都可以 最终还是通过 setValue() 设置的
             * */ 
            data.postValue("postValue12345")
            data.setValue("setValue12345")
        }
    }
}

        LiveData는 추상 클래스이며 인스턴스를 만들 수 없으므로 하위 클래스 MutableLiveData를 사용하여 LiveData를 만듭니다.

        분명히 이것은 관찰자 패턴입니다. LiveData는 observe()를 통해 모니터링 데이터를 등록하고, setValue / postValue를 통해 데이터를 설정합니다. 실제로 postValue()는 setValue()에 의해 최종적으로 설정됩니다. 그것을 사용한 친구들은 그들이 모두 그것을 알고 있다고 믿습니다.

        하지만 이 글은 그것을 어떻게 사용하는지 보는 것이 아니라 LiveData의 소스 코드를 탐색하여 이것이 어떻게 호스트 수명 주기에 연결되어 있는지 알아보는 것입니다.

  네 가지 질문         으로 소스 코드를 살펴보겠습니다   .

        【질문 1】: 모니터링을 수동으로 취소하지 않고 호스트 활동 또는 Framgent를 파괴하는 방법은 무엇입니까?

        [ 질문 2 ]: 호스트 활동 또는 Framgent가 표시될 때만 수신기에 새 데이터를 보내는 방법은 무엇입니까?

        [ 질문 3 ]: 호스트 활동 또는 Framgent가 표시되지 않을 때 데이터를 설정하고 새 데이터를 수신기에 즉시 보내지 않고 활동 또는 Framgent가 다시 표시될 때 수신기에 새 데이터를 보내는 방법은 무엇입니까?

        [ 질문 4 ]: 호스트 Activity 또는 Framgent가 다시 표시될 때 데이터가 다시 업데이트되는 경우에만 관찰자에게 데이터를 보내는 방법 및 데이터가 업데이트되지 않은 경우 수신기에 알리지 않음

-------------------1부-------------------------

먼저 모니터에 등록할 때 어떤 로직이 수행되는지 살펴보고 LiveData.observe()의 소스 코드를 살펴보겠습니다.

    

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer){
        // ---------------注释1 ---------------
        assertMainThread("observe");
        // ---------------注释2 ---------------
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }

        //  注释3 这个是重点 大部分逻辑在这个 LifecycleBoundObserver 里面
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

        // ---------------注释4 ---------------
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }

        // ---------------注释5 ---------------
        owner.getLifecycle().addObserver(wrapper);
    }

[ 참고 1 ]: 감지는 메인 스레드에서 모니터링해야 하며 그렇지 않으면 예외가 발생하므로 LiveData 모니터링은 메인 스레드에서 수행해야 합니다.관심 있는 학생들은 들어가서 볼 수 있습니다.내부 코드는 매우 간단합니다.

[ 참고 2 ]: 현재 호스트 LifecycleOwner(즉, Activity / Framgent)가 이미 파괴 상태에 있는 경우 모니터링을 위해 등록하고 바로 종료할 필요가 없습니다. 설명이 필요 없는 논리

[ 참고 3 ]: LiveData 의 LifecycleOwner 와 Observer 를 LifecycleBoundObserver 를 통해 Bind 하여 LiveData 의 LifecycleOwner 와 Observer 의 Life Cycle 을 서로 연결할 수 있도록 합니다.

참고 4】: 생성된 LiveData 리스너를 mObservers에 저장합니다. 나중에 데이터 변경이 있을 때 mObservers의 각 요소가 순회되고 새 데이터가 자격 있는 수신기에 하나씩 전송됩니다.

[ 참고 5 ]: LifecycleOwner는 수명 주기를 모니터링하고 수명 주기 상태 변경에 대한 콜백은 모두 LifecycleBoundObserver에서 콜백됩니다.

따라서 이 부분을 요약하면 LifecycleBoundObserver는 LifecycleOwner와 LiveData 수신기를 함께 바인딩하여 수신기가 Activity/Fragment의 수명 주기를 인식할 수 있도록 합니다.

-------------------2부--------------------------------------

위에서 언급한 LifecycleBoundObserver를 살펴보고 이 LifecycleBoundObserver가 어떻게 구현되는지 살펴보겠습니다.

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {

        //省略无关紧要的代码.....................

        @Override
        boolean shouldBeActive() {
            // 这里的意思是只有在LifecycleOwner(Activity / Fragment) 可见时才会返回 true
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        // ----------------注释1---------------
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            // ----------------注释2---------------
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            // ----------------注释3---------------
            activeStateChanged(shouldBeActive());
        }

        //省略无关紧要的代码.....................
    }



    private abstract class ObserverWrapper {

    	//省略无关紧要的代码.....................
       
        
        void activeStateChanged(boolean newActive) {
            // 状态和之前一样不执行,这个很合理
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                // 空实现,可以重写此方法自己执行自己的拓展业务逻辑
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                // 同样空实现,可以重写此方法自己执行自己的拓展业务逻辑
                onInactive();
            }
            if (mActive) {
                // ----------------注释4--------------- 
                dispatchingValue(this);
            }
        }
    }

일부 관련 없는 코드를 생략하면 LifecycleBoundObserver가 ObserverWrapper에 통합되고 LifecycleEventObserver 인터페이스를 구현하는 것을 볼 수 있습니다.

[ 참고 1 ]: 호스트 LifecycleOwner(예: Activity / Framgent)의 수명 주기 변경은 [ Part1 ] 참고 5 의 역할인 참고 1의 onStateChanged() 메서드를 통해 다시 호출됩니다. 참고 5 owner.getLifecycle() .addObserver(래퍼)

[ Note 2 ]: 호스트 LifecycleOwner(예: Activity / Framgent)의 수명 주기가 소멸되면 수신기가 제거됩니다. 이 [ Part1 ] Note 4는 관찰자 모드의 모니터링 및 취소에 해당합니다. 이것은 우리의 [ 질문 1 ](모니터를 수동으로 취소하지 않고 호스트 활동 또는 Framgent를 파괴하는 방법?)을 설명합니다.

[ 참고 3 ]: 상태 변경은 마침내 activeStateChanged() 를 호출 합니다. 이 메서드는 LifecycleBoundObserver의 부모 클래스인 ObserverWrapper에 있습니다. 여기의 논리는 부모 클래스의 코드에서 명확합니다. 그러나 매개변수가 여기에 전달되며 이는 shouldBeActive() 를 통해 얻습니다. 내부 논리에 관심이 있는 학생은 직접 들어가서 살펴볼 수 있습니다. 즉, LifecycleOwner(예: Activity / Framgent)가 보인다.

[ 참고 4 ]: 마지막으로 dispatchingValue()는 리스너에게 알리지만 여기에는 조건이 있습니다. 즉, LifecycleOwner(즉: Activity / Framgent)가 보일 때 true가 되고, dispatchingValue()가 실행되어 리스너에게 알리게 되는데, 이것이 [ 질문 2 ]와 [ 질문 3 ]입니다. 보이지 않으면 알리지 않고, 다시 보이면 다시 알려준다.

여기에서 우리가 쉽게 질문할 수 있는 부분이 있습니다. 활동/Framgent가 다시 표시될 때마다 관찰자에게 알립니까? 데이터에 변경 사항이 있는 경우 통지하는 것이 합리적이며 변경 사항이 없는 경우 통지할 필요가 없습니다. 이것이 우리의 문제입니다[ 질문 4 ]. 사실 위에서 언급한 dispatchingValue()  메서드 에 모두 있습니다.

-------------------3부---------------------------------------

좋습니다. dispatchingValue() 내부의 논리를 살펴보겠습니다.

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                //--------注释1 执行通知
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    //--------注释2 执行通知
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }



   private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        // ----- 注释3 当前 Version 是否已经发送过,发送过退出不需要发送
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        // ----- 注释4 保存当前 Version 表示当前数据已经发送给观察者了 
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }

실제로 dispatchingValue()  는 모든 관찰자를 순회하고 관찰자에게 데이터를 보내는 것입니다. 주로 [ 주 1 ] 및 [ 주 2 ] 를 참조하십시오 . 이는 실행하여 관찰자에게 보내는 것이지만 이 단계는 여전히 우리를 보지 못합니다 [ 질문 4 ] 답변.

[ 참고 1 ] 및 [ 참고 2 ] 에서 입력한 thinkNotify() 메서드를 입력 하면 현재 데이터가 전송되었는지 여부를 판단하는  [ 참고 3 ] 및 [ 참고 4 ]를 볼 수 있습니다 . 설정되어 있고 참조를 검색하면 LiveData.setValue() 중에 설정되어 있는 것을 확인할 수 있습니다. postValue()는 setValue()를 통해 최종적으로 설정되기 때문에 데이터를 설정하는 데 사용되는 메서드는 LiveData.setValue()로 실행됩니다.

    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

한눈에 봐도 알록달록,,,,,,,,,

따라서 [ 질문 4 ] 전체 프로세스는 다음과 같습니다. 각 LiveDate는 버전 저장에 해당하며 LiveDate가 데이터를 설정할 때마다 해당 버전이 1씩 증가하고 데이터가 관찰자에게 전송되면 버전이 저장됩니다. Activity가 비가시 상태에서 가시 상태로 돌아올 때 저장된 버전이 LiveDate 버전과 일치하는지 여부를 판단합니다. 일치하는 경우 데이터가 이미 관찰자에게 전송되었음을 의미하며 중복 전송되지 않습니다. 일치하지 않는 경우에만 새 데이터가 관찰자에게 전송됩니다. 이것이 Activity / Fragment가 보이지 않는 상태에서 보이는 상태로 여러 번 돌아오더라도 동일한 데이터를 한 번만 관찰자에게 보내는 이유입니다. 이것이 우리가 찾고 있는 [ 질문 4 ] 에 대한 답변입니다.

위의 코드 논리가 잘못된 경우 지적 메시지를 남겨주세요. 감사합니다.

Guess you like

Origin blog.csdn.net/Leo_Liang_jie/article/details/120435596