[Android/Kotlin] SingleLiveEvent
イベントをViewModelからViewに渡す場合は、値を渡すのではなくイベントだけを渡します.
class ListViewModel : ViewModel {
private val _navigateToDetails = SingleLiveEvent<Any>()
val navigateToDetails : LiveData<Any>
get() = _navigateToDetails
fun userClicksOnButton() {
_navigateToDetails.call()
}
}
in View
myViewModel.navigateToDetails.observe(this, Observer {
if (it) startActivity(DetailsActivity...)
})
SingleLiveEventというMutableLiveDataを継承するクラスを作成します.変更データの論理を内部に配置してイベントを励起し、外部にcall()を呼び出す.
関数のパラメータが必要な場合は、JENERIC Tを定義してsetValue()を使用することもできます.
sample 1
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private static final long MIN_CLICK_INTERVAL = 200;
private long lastClickTime;
private final AtomicBoolean mPending = new AtomicBoolean(false);
...
@MainThread
public void setValue(@Nullable T t) {
long currentClickTime = SystemClock.uptimeMillis();
long elapsedTime = currentClickTime - lastClickTime;
lastClickTime = currentClickTime;
if(elapsedTime <=MIN_CLICK_INTERVAL){
return;
}
mPending.set(true);
super.setValue(t);
}
...
}
既存のSingleLiveEventコードとほぼ同じで、最後のイベント処理時刻を記録し、現在時刻と比較してThreshold(しきい値)を超えるかどうかをチェックして呼び出します.特に何もありませんが、DatabindingやRxJavaへの依存性を解消できるので、とても快適になります.
postValue(T)は使用可能であるが,閾値が保証されないため,この方法が最も信頼できる方法であると考えられる.
sample 2
import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
class SingleLiveEvent<T> : MutableLiveData<T>() {
/**
* 멀티쓰레딩 환경에서 동시성을 보장하는 AtomicBoolean.
* false로 초기화되어 있음
*/
private val pending = AtomicBoolean(false)
/**
* View(Activity or Fragment 등 LifeCycleOwner)가 활성화 상태가 되거나
* setValue로 값이 바뀌었을 때 호출되는 observe 함수.
* pending.compareAndSet(true, false)라는 것은, 위의 pending 변수가
* true면 if문 내의 로직을 처리하고 false로 바꾼다는 것이다.
*
* 아래의 setValue를 통해서만 pending값이 true로 바뀌기 때문에,
* Configuration Changed가 일어나도 pending값은 false이기 때문에 observe가
* 데이터를 전달하지 않는다!
*/
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
// Observe the internal MutableLiveData
super.observe(owner, Observer { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
})
}
/**
* LiveData로써 들고있는 데이터의 값을 변경하는 함수.
* 여기서는 pending(AtomicBoolean)의 변수는 true로 바꾸어
* observe내의 if문을 처리할 수 있도록 하였음.
*/
@MainThread
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
/**
* 데이터의 속성을 지정해주지 않아도 call만으로 setValue를 호출 가능
*/
@MainThread
fun call() {
value = null
}
companion object {
private val TAG = "SingleLiveEvent"
}
}
リファレンスhttps://velog.io/@hhi-5258/AAC-SingleLiveEvent
https://zladnrms.tistory.com/146
Reference
この問題について([Android/Kotlin] SingleLiveEvent), 我々は、より多くの情報をここで見つけました https://velog.io/@hyom/AndroidKotlin-SingleLiveEventテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol