/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.trello.rxlifecycle.android; import android.support.annotation.CheckResult; import android.support.annotation.NonNull; import android.view.View; import com.jakewharton.rxbinding.view.RxView; import com.trello.rxlifecycle.*; import rx.Observable; import rx.functions.Func1; import static com.trello.rxlifecycle.RxLifecycle.bind; import static com.trello.rxlifecycle.internal.Preconditions.checkNotNull; public class RxLifecycleAndroid { private RxLifecycleAndroid() { throw new AssertionError("No instances"); } /** * Binds the given source to an Activity lifecycle. * <p> * Use with {@link Observable#compose(Observable.Transformer)}: * {@code source.compose(RxLifecycleAndroid.bindActivity(lifecycle)).subscribe()} * <p> * This helper automatically determines (based on the lifecycle sequence itself) when the source * should stop emitting items. In the case that the lifecycle sequence is in the * creation phase (CREATE, START, etc) it will choose the equivalent destructive phase (DESTROY, * STOP, etc). If used in the destructive phase, the notifications will cease at the next event; * for example, if used in PAUSE, it will unsubscribe in STOP. * <p> * Due to the differences between the Activity and Fragment lifecycles, this method should only * be used for an Activity lifecycle. * * @param lifecycle the lifecycle sequence of an Activity * * @return a reusable {@link Observable.Transformer} that unsubscribes the source during the Activity lifecycle */ @NonNull @CheckResult public static <T> LifecycleTransformer<T> bindActivity(@NonNull final Observable<ActivityEvent> lifecycle) { return bind(lifecycle, ACTIVITY_LIFECYCLE); } /** * Binds the given source to a Fragment lifecycle. * <p> * Use with {@link Observable#compose(Observable.Transformer)}: * {@code source.compose(RxLifecycleAndroid.bindFragment(lifecycle)).subscribe()} * <p> * This helper automatically determines (based on the lifecycle sequence itself) when the source * should stop emitting items. In the case that the lifecycle sequence is in the * creation phase (CREATE, START, etc) it will choose the equivalent destructive phase (DESTROY, * STOP, etc). If used in the destructive phase, the notifications will cease at the next event; * for example, if used in PAUSE, it will unsubscribe in STOP. * <p> * Due to the differences between the Activity and Fragment lifecycles, this method should only * be used for a Fragment lifecycle. * * @param lifecycle the lifecycle sequence of a Fragment * @return a reusable {@link Observable.Transformer} that unsubscribes the source during the Fragment lifecycle */ @NonNull @CheckResult public static <T> LifecycleTransformer<T> bindFragment(@NonNull final Observable<com.trello.rxlifecycle.android.FragmentEvent> lifecycle) { return bind(lifecycle, FRAGMENT_LIFECYCLE); } /** * Binds the given source to a View lifecycle. * <p> * Specifically, when the View detaches from the window, the sequence will be completed. * <p> * Use with {@link Observable#compose(Observable.Transformer)}: * {@code source.compose(RxLifecycleAndroid.bindView(lifecycle)).subscribe()} * <p> * Warning: you should make sure to use the returned Transformer on the main thread, * since we're binding to a View (which only allows binding on the main thread). * * @param view the view to bind the source sequence to * @return a reusable {@link Observable.Transformer} that unsubscribes the source during the View lifecycle */ @NonNull @CheckResult public static <T> LifecycleTransformer<T> bindView(@NonNull final View view) { checkNotNull(view, "view == null"); return bind(RxView.detaches(view)); } // Figures out which corresponding next lifecycle event in which to unsubscribe, for Activities private static final Func1<ActivityEvent, ActivityEvent> ACTIVITY_LIFECYCLE = new Func1<ActivityEvent, ActivityEvent>() { @Override public ActivityEvent call(ActivityEvent lastEvent) { switch (lastEvent) { case CREATE: return ActivityEvent.DESTROY; case START: return ActivityEvent.STOP; case RESUME: return ActivityEvent.PAUSE; case PAUSE: return ActivityEvent.STOP; case STOP: return ActivityEvent.DESTROY; case DESTROY: throw new OutsideLifecycleException("Cannot bind to Activity lifecycle when outside of it."); default: throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented"); } } }; // Figures out which corresponding next lifecycle event in which to unsubscribe, for Fragments private static final Func1<com.trello.rxlifecycle.android.FragmentEvent, com.trello.rxlifecycle.android.FragmentEvent> FRAGMENT_LIFECYCLE = new Func1<com.trello.rxlifecycle.android.FragmentEvent, com.trello.rxlifecycle.android.FragmentEvent>() { @Override public com.trello.rxlifecycle.android.FragmentEvent call( com.trello.rxlifecycle.android.FragmentEvent lastEvent) { switch (lastEvent) { case ATTACH: return com.trello.rxlifecycle.android.FragmentEvent.DETACH; case CREATE: return com.trello.rxlifecycle.android.FragmentEvent.DESTROY; case CREATE_VIEW: return com.trello.rxlifecycle.android.FragmentEvent.DESTROY_VIEW; case START: return com.trello.rxlifecycle.android.FragmentEvent.STOP; case RESUME: return com.trello.rxlifecycle.android.FragmentEvent.PAUSE; case PAUSE: return com.trello.rxlifecycle.android.FragmentEvent.STOP; case STOP: return com.trello.rxlifecycle.android.FragmentEvent.DESTROY_VIEW; case DESTROY_VIEW: return com.trello.rxlifecycle.android.FragmentEvent.DESTROY; case DESTROY: return com.trello.rxlifecycle.android.FragmentEvent.DETACH; case DETACH: throw new OutsideLifecycleException("Cannot bind to Fragment lifecycle when outside of it."); default: throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented"); } } }; }