android/Jetpack

3. LiveData

android by kotlin 2022. 10. 3. 11:12

*개인적으로 분석한 내용이므로 틀린 내용이 있을 수 있습니다. 틀린 내용을 댓글로 남겨주시면 수정하도록 하겠습니다!

 

[1]. LiveData 의존성 선언

dependencies {
	...

    // LiveData 
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.0-alpha02"
	...
}

 

[2]. LiveData 사용방법

 

class MainViewModel : ViewModel() {
    private var _flag = MutableLiveData<Boolean>()
	/*
		ViewModel 클래스 외부에 노출될 LiveData 프로퍼티는 
		변경이 불가능한 LiveData 타입을 사용한다.
	*/
    val flag: LiveData<Boolean> get() = _flag

	/*
		LiveData 를 관찰하고 있는 옵저버가
		데이터가 변경되었음을 통지받을 수 있도록
		LiveData 의 setValue 메서드를 사용하여 
		데이터를 변경시킨다.
	*/
    fun change() {
        _flag.value = _flag.value != true
    }
}
class MainActivity : AppCompatActivity() {
    private val binding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }
    private val viewModel by lazy {
        ViewModelProvider(this).get(MainViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        initViews()
        initObserver()
    }

    private fun initViews() {
		/*
			버튼을 클릭한 경우
			ViewModel 클래스의 change 메서드를 호출한다.
		*/
        binding.switchButton.setOnClickListener {
            viewModel.change()
        }
    }

    private fun initObserver() {
		/*
			ViewModel 클래스의 _flag LiveData 가 변경되었을 경우
			변경 사항을 통지받기 위해 옵저버를 등록시켜놓는다.
			첫번째 매개변수는 생명주기 소유자 객체로 
			생명주기가 활성화 상태일 경우에만 통지를 받기위해 전달하는 매개변수이다.
		*/
        viewModel.flag.observe(this) { flag ->
            if(flag) {
                binding.switchButton.text = "true"
            } else {
                binding.switchButton.text = "false"
            }
        }
    }
}

 

[3]. LiveData 옵저버 등록 분석

 

1. LiveData 의 observe 메서드의 동작 과정을 간략히 요약하면 LiveData 의 옵저버 Map 에 등록생명주기 소유자의 생명주기를 관찰하기 위해 Lifecycle 옵저버 등록초기값을 옵저버에 통지 하는 과정을 거치게 된다.

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
	/*
		옵저버를 등록한 생명주기 소유자의 상태가 DESTROYED 상태라면
		통지를 받지 않도록 한다.
	*/
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
		// ignore
		return;
	}
	LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
	
	/*
		해당 옵저버를 Map 자료구조인 mObservers 에 등록한다.
	*/
	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;
	}
	
	/*
		생명주기 소유자의 생명주기 변화에 따라 옵저버의 callback 메서드를 호출하기 위해서
		생명주기에 옵저버를 바인딩한다.
	*/
	owner.getLifecycle().addObserver(wrapper);
}

 

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
	enforceMainThreadIfNeeded("addObserver");
	State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
	ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
	ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

	if (previous != null) {
		return;
	}
	LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
	if (lifecycleOwner == null) {
		// it is null we should be destroyed. Fallback quickly
		return;
	}

	boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
	
	State targetState = calculateTargetState(observer);
	mAddingObserverCounter++;
	
	//DESTROYED == 0, INITIALIZED == 1, CREATED == 2, STARTED == 3, RESUMED == 4
	
	/*
		현재 옵저버의 생명주기가 CREATED 이상인 경우 그리고 해당 옵저버가 등록되어 있는 경우에만
		while 구문을 실행하여 옵저버에 이벤트를 디스패치한다.
	*/
	while ((statefulObserver.mState.compareTo(targetState) < 0
		&& mObserverMap.contains(observer))) {
		pushParentState(statefulObserver.mState);
		final Event event = Event.upFrom(statefulObserver.mState);
		if (event == null) {
			throw new IllegalStateException("no event up from " + statefulObserver.mState);
		}
		statefulObserver.dispatchEvent(lifecycleOwner, event);
		popParentState();
		// mState / subling may have been changed recalculate
		targetState = calculateTargetState(observer);
	}

	if (!isReentrance) {
		// we do sync only on the top level.
		sync();
	}
	mAddingObserverCounter--;
}
void dispatchEvent(LifecycleOwner owner, Event event) {
	State newState = event.getTargetState();
	mState = min(mState, newState);
	
	/*
		옵저버의 onStateChanged 메서드를 호출한다.
	*/
	mLifecycleObserver.onStateChanged(owner, event);
	mState = newState;
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
	@NonNull Lifecycle.Event event) {
	Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
	
	if (currentState == DESTROYED) {
		removeObserver(mObserver);
		return;
	}
	Lifecycle.State prevState = null;
	while (prevState != currentState) {
		prevState = currentState;
		activeStateChanged(shouldBeActive());
		currentState = mOwner.getLifecycle().getCurrentState();
	}
}
void activeStateChanged(boolean newActive) {
	//새로운 상태와 기존 상태가 동일하다면 종료한다.
	if (newActive == mActive) {
		return;
	}
	// immediately set active state, so we'd never dispatch anything to inactive
	// owner
	
	//옵저버의 상태를 업데이트한다.
	mActive = newActive;
	
	changeActiveCounter(mActive ? 1 : -1);
	
	/*
		활성 상태로 업데이트된 경우 
		옵저버에게 한번 통지하기 위해 dispatchingValue 메서드를 호출한다.
	*/
	if (mActive) {
		dispatchingValue(this);
	}
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
	if (mDispatchingValue) {
		mDispatchInvalidated = true;
		return;
	}
	mDispatchingValue = true;
	do {
		mDispatchInvalidated = false;
		/*
			옵저버 등록 후 최초의 dispatchingValue 호출 시에는
			initiator 객체가 null 이 아니므로 if 조건을 수행한다
		*/
		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;
}
@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;
	
	/*
		옵저버 등록 시 전달한 객체의 callback 메서드를 호출하여
		Activity 또는 Fragment 에서 초기값을 이용하여 View 를 업데이트할 수 있도록 한다
	*/
	observer.mObserver.onChanged((T) mData);
}

 

[4]. LiveData 의 값 변화 시 분석 내용

 

1. LiveData 의 setValue 메서드를 호출하여 값을 변경하게 되면 해당 LiveData 를 관찰하고 있는 모든 옵저버들에게 값이 변경되었음을 통지하게 된다.

class MainViewModel : ViewModel() {
    private var _flag = MutableLiveData<Boolean>()
    val flag: LiveData<Boolean> get() = _flag

	/*
		LiveData 의 setValue 를 호출한다.
	*/
    fun change() {
        _flag.value = _flag.value != true
    }
}
@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 {
			/*
				setValue 를 호출하는 경우에는 initiator 객체가 null 이므로
				mObservers 를 통해 해당 LiveData 를 관찰하는 옵저버들을 하나씩 꺼내서
				값이 변화되었다는 것을 옵저버에게 통지해주기 위해 onChanged callback 메서드를 호출해준다.
			*/
			for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
				mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
					considerNotify(iterator.next().getValue());
					if (mDispatchInvalidated) {
						break;
					}
				}
			}
		} while (mDispatchInvalidated);
	mDispatchingValue = false;
}

 

[5]. LiveData 옵저버 제거 분석 내용

 

 1. 생명주기 소유자의 생명주기가 DESTROYED 상태가 되거나 명시적으로 removeObserver 를 호출하는 경우 removeObserver 메서드를 호출하여 옵저버를 제거한다.

@Override
public void onStateChanged(@NonNull LifecycleOwner source,
	@NonNull Lifecycle.Event event) {
	Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
	/*
		생명주기 소유자의 생명주기가 DESTROYED 상태인 경우 LiveData 에 등록된 옵저버를 제거한다.
	*/
	if (currentState == DESTROYED) {
		removeObserver(mObserver);
		return;
	}
	Lifecycle.State prevState = null;
	while (prevState != currentState) {
		prevState = currentState;
		activeStateChanged(shouldBeActive());
		currentState = mOwner.getLifecycle().getCurrentState();
	}
}
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
	assertMainThread("removeObserver");
	/*
		해당 LiveData 를 관찰중인 옵저버를 제거한다.
	*/
	ObserverWrapper removed = mObservers.remove(observer);
	if (removed == null) {
		return;
	}
	removed.detachObserver();
	removed.activeStateChanged(false);
}