Last active
March 28, 2021 16:55
-
-
Save bensandee/58c717aa2a8d9e02d8841671070210c8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.arch.lifecycle.ViewModel | |
import android.os.Looper | |
import android.support.annotation.CallSuper | |
import com.google.errorprone.annotations.CheckReturnValue | |
import com.uber.autodispose.CompletableSubscribeProxy | |
import com.uber.autodispose.FlowableSubscribeProxy | |
import com.uber.autodispose.LifecycleNotStartedException | |
import com.uber.autodispose.MaybeSubscribeProxy | |
import com.uber.autodispose.ObservableSubscribeProxy | |
import com.uber.autodispose.ScopeProvider | |
import com.uber.autodispose.SingleSubscribeProxy | |
import io.reactivex.Completable | |
import io.reactivex.Flowable | |
import io.reactivex.Maybe | |
import io.reactivex.MaybeObserver | |
import io.reactivex.Observable | |
import io.reactivex.Single | |
import io.reactivex.android.MainThreadDisposable | |
import java.util.concurrent.TimeUnit | |
import com.uber.autodispose.kotlin.autoDisposable | |
class MyViewModel : BaseViewModel() { | |
init { | |
Observable.interval(10, TimeUnit.SECONDS) | |
.autoDisposable() | |
.subscribe { | |
// do something | |
} | |
} | |
} | |
abstract class BaseViewModel : ViewModel() { | |
protected val autoDisposeViewModelDelegate by lazy { AutoDisposeViewModelDelegate() } | |
protected val scopeProvider by lazy { AutoDisposeViewModelScopeProvider(autoDisposeViewModelDelegate) } | |
@CallSuper | |
override fun onCleared() { | |
super.onCleared() | |
autoDisposeViewModelDelegate.onCleared() | |
} | |
// I like to use these extensions to simplify the calls, but they don't really save that much | |
@CheckReturnValue | |
protected fun <T> Observable<T>.autoDisposable(): ObservableSubscribeProxy<T> = | |
autoDisposable(scopeProvider) | |
@CheckReturnValue | |
protected fun <T> Flowable<T>.autoDisposable(): FlowableSubscribeProxy<T> = | |
this.autoDisposable(scopeProvider) | |
@CheckReturnValue | |
protected fun <T> Maybe<T>.autoDisposable(): MaybeSubscribeProxy<T> = | |
this.autoDisposable(scopeProvider) | |
@CheckReturnValue | |
protected fun Completable.autoDisposable(): CompletableSubscribeProxy = | |
this.autoDisposable(scopeProvider) | |
@CheckReturnValue | |
protected fun <T> Single<T>.autoDisposable(): SingleSubscribeProxy<T> = | |
this.autoDisposable(scopeProvider) | |
} | |
/** keep all the autodispose stuff in a simple delegate making it easier to compose into existing ViewModel hierarchies */ | |
class AutoDisposeViewModelDelegate { | |
private val clearListeners: MutableList<OnClearListener> = mutableListOf() | |
private var cleared = false | |
fun onCleared() { | |
cleared = true | |
clearListeners.forEach { | |
it.onClear() | |
} | |
clearListeners.clear() | |
} | |
private interface OnClearListener { | |
fun onClear() | |
} | |
/** adapted/borrowed liberally from viewdetachedmaybe */ | |
internal class ClearedEventMaybe(private val delegate: AutoDisposeViewModelDelegate) : Maybe<Unit>() { | |
override fun subscribeActual(observer: MaybeObserver<in Unit>) { | |
val listener = Listener(delegate, observer) | |
observer.onSubscribe(listener) | |
// Check we're on the main thread. | |
if (Looper.myLooper() != Looper.getMainLooper()) { | |
observer.onError(IllegalStateException("ViewModels can only be bound to on the main thread!")) | |
return | |
} | |
// Check that it's not cleared. | |
if (delegate.cleared) { | |
observer.onError(LifecycleNotStartedException("ViewModel is cleared!")) | |
return | |
} | |
if(!listener.isDisposed) { | |
delegate.clearListeners += listener | |
} | |
} | |
} | |
internal class Listener(private val delegate: AutoDisposeViewModelDelegate, private val observer: MaybeObserver<in Unit>) : | |
MainThreadDisposable(), | |
OnClearListener { | |
override fun onClear() { | |
if (!isDisposed) { | |
observer.onSuccess(Unit) | |
} | |
} | |
override fun onDispose() { | |
delegate.clearListeners -= this | |
} | |
} | |
} | |
class AutoDisposeViewModelScopeProvider(private val delegate: AutoDisposeViewModelDelegate) : ScopeProvider { | |
override fun requestScope(): Maybe<*> { | |
return AutoDisposeViewModelDelegate.ClearedEventMaybe(delegate) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment