Skip to content

Commit

Permalink
Make AndroidLifecycleScopeProvider reusable by deferring backfill to …
Browse files Browse the repository at this point in the history
…peekLifecycle (#121)

* Make AndroidLifecycleScopeProvider reusable by backfilling from peek

This moves backfilling out of a one-time thing in the constructor to something we do every time the lifecycle is peeked. It feels a bit weird though, but perhaps necessary because of the fact that arch lifecycle events are emitted _after_ the corresponding callback method.

Resolves #114

* Fix imports

* Clean up doc
  • Loading branch information
ZacSweers authored Oct 23, 2017
1 parent 4a1d96d commit 31a55c5
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public final class AndroidLifecycleScopeProvider
case ON_STOP:
case ON_DESTROY:
default:
throw new LifecycleEndedException();
throw new LifecycleEndedException("Lifecycle has ended! Last event was " + lastEvent);
}
}
};
Expand Down Expand Up @@ -145,6 +145,7 @@ private AndroidLifecycleScopeProvider(Lifecycle lifecycle,
}

@Override public Lifecycle.Event peekLifecycle() {
lifecycleObservable.backfillEvents();
return lifecycleObservable.getValue();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
import io.reactivex.android.MainThreadDisposable;
import io.reactivex.subjects.BehaviorSubject;

import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
import static android.arch.lifecycle.Lifecycle.Event.ON_START;
import static android.support.annotation.RestrictTo.Scope.LIBRARY;
import static com.uber.autodispose.android.internal.AutoDisposeAndroidUtil.isMainThread;

Expand All @@ -38,33 +42,38 @@

@SuppressWarnings("CheckReturnValue") LifecycleEventsObservable(Lifecycle lifecycle) {
this.lifecycle = lifecycle;
// Backfill if already created for boundary checking
// We do a trick here for corresponding events where we pretend something is created
// upon initialized state so that it assumes the corresponding event is DESTROY.
@Nullable Event correspondingEvent;
}

Event getValue() {
return eventsObservable.getValue();
}

/**
* Backfill if already created for boundary checking. We do a trick here for corresponding events
* where we pretend something is created upon initialized state so that it assumes the
* corresponding event is DESTROY.
*/
void backfillEvents() {
@Nullable Lifecycle.Event correspondingEvent;
switch (lifecycle.getCurrentState()) {
case INITIALIZED:
correspondingEvent = Event.ON_CREATE;
correspondingEvent = ON_CREATE;
break;
case CREATED:
correspondingEvent = Event.ON_START;
correspondingEvent = ON_START;
break;
case STARTED:
case RESUMED:
correspondingEvent = Event.ON_RESUME;
correspondingEvent = ON_RESUME;
break;
case DESTROYED:
default:
correspondingEvent = Event.ON_DESTROY;
correspondingEvent = ON_DESTROY;
break;
}
eventsObservable.onNext(correspondingEvent);
}

Event getValue() {
return eventsObservable.getValue();
}

@Override protected void subscribeActual(Observer<? super Event> observer) {
if (!isMainThread()) {
observer.onError(
Expand Down Expand Up @@ -96,8 +105,8 @@ static final class ArchLifecycleObserver extends MainThreadDisposable

@OnLifecycleEvent(Event.ON_ANY) void onStateChange(LifecycleOwner owner, Event event) {
if (!isDisposed()) {
if (!(event == Event.ON_CREATE && eventsObservable.getValue() == event)) {
// Due to the INITIALIZED->ON_CREATE mapping trick we do in the constructor backfill,
if (!(event == ON_CREATE && eventsObservable.getValue() == event)) {
// Due to the INITIALIZED->ON_CREATE mapping trick we do in backfill(),
// we fire this conditionally to avoid duplicate CREATE events.
eventsObservable.onNext(event);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ import java.util.concurrent.TimeUnit
*/
class KotlinActivity : AppCompatActivity() {

// Can be reused
private val scopeProvider by lazy { AndroidLifecycleScopeProvider.from(this) }

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d(TAG, "onCreate()")
Expand All @@ -41,7 +44,7 @@ class KotlinActivity : AppCompatActivity() {
// dispose is onDestroy (the opposite of onCreate).
Observable.interval(1, TimeUnit.SECONDS)
.doOnDispose { Log.i(TAG, "Disposing subscription from onCreate()") }
.autoDisposeWith(AndroidLifecycleScopeProvider.from(this))
.autoDisposeWith(scopeProvider)
.subscribe { num -> Log.i(TAG, "Started in onCreate(), running until onDestroy(): " + num) }
}

Expand All @@ -54,7 +57,7 @@ class KotlinActivity : AppCompatActivity() {
// dispose is onStop (the opposite of onStart).
Observable.interval(1, TimeUnit.SECONDS)
.doOnDispose { Log.i(TAG, "Disposing subscription from onStart()") }
.autoDisposeWith(AndroidLifecycleScopeProvider.from(this))
.autoDisposeWith(scopeProvider)
.subscribe { num -> Log.i(TAG, "Started in onStart(), running until in onStop(): " + num) }
}

Expand All @@ -67,7 +70,7 @@ class KotlinActivity : AppCompatActivity() {
// dispose is onPause (the opposite of onResume).
Observable.interval(1, TimeUnit.SECONDS)
.doOnDispose { Log.i(TAG, "Disposing subscription from onResume()") }
.autoDisposeWith(AndroidLifecycleScopeProvider.from(this))
.autoDisposeWith(scopeProvider)
.subscribe { num ->
Log.i(TAG, "Started in onResume(), running until in onPause(): " + num)
}
Expand Down

0 comments on commit 31a55c5

Please sign in to comment.