diff --git a/app/src/main/java/keijumt/devandroid/databinding/SingleLiveEvent.kt b/app/src/main/java/keijumt/devandroid/databinding/SingleLiveEvent.kt new file mode 100644 index 0000000..1c3598b --- /dev/null +++ b/app/src/main/java/keijumt/devandroid/databinding/SingleLiveEvent.kt @@ -0,0 +1,59 @@ +package keijumt.devandroid.databinding + +import android.arch.lifecycle.LifecycleOwner +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.Observer +import android.support.annotation.MainThread +import android.util.Log +import java.util.concurrent.atomic.AtomicBoolean + +/** + * A lifecycle-aware observable that sends only new updates after subscription, used for events like + * navigation and Snackbar messages. + * + * + * This avoids a common problem with events: on configuration change (like rotation) an update + * can be emitted if the observer is active. This LiveData only calls the observable if there's an + * explicit call to setValue() or call(). + * + * + * Note that only one observer is going to be notified of changes. + */ +class SingleLiveEvent : MutableLiveData() { + + private val mPending = AtomicBoolean(false) + + @MainThread + override fun observe(owner: LifecycleOwner, observer: Observer) { + + 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 (mPending.compareAndSet(true, false)) { + observer.onChanged(t) + } + }) + } + + @MainThread + override fun setValue(t: T?) { + mPending.set(true) + super.setValue(t) + } + + /** + * Used for cases where T is Void, to make calls cleaner. + */ + @MainThread + fun call() { + value = null + } + + companion object { + + private val TAG = "SingleLiveEvent" + } +} \ No newline at end of file