Skip to content

Commit

Permalink
Merge pull request #216 from evant/android-lifecycle
Browse files Browse the repository at this point in the history
 Added support for android-lifecycle
  • Loading branch information
dlew authored May 27, 2017
2 parents 9f7ee07 + c11d585 commit 7b6a3ef
Show file tree
Hide file tree
Showing 21 changed files with 665 additions and 9 deletions.
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ You have a few options for that:

1. Use rxlifecycle-components and subclass the provided `RxActivity`, `RxFragment`, etc. classes.
1. Use [Navi](https://github.com/trello/navi/) + rxlifecycle-navi to generate providers.
1. Use [Android's lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle.html) + rxlifecycle-android-lifecycle to generate providers.
1. Write the implementation yourself.

If you use rxlifecycle-components, just extend the appropriate class, then use the built-in `bindToLifecycle()` (or `bindUntilEvent()`) methods:
Expand Down Expand Up @@ -79,6 +80,23 @@ public class MyActivity extends NaviActivity {
}
```

If you use rxlifecycle-android-lifecycle, then you just pass your `LifecycleOwner` to `AndroidLifecycle` to generate a provider:

```java
public class MyActivity extends LifecycleActivity {
private final LifecycleProvider<Lifecycle.Event> provider
= AndroidLifecycle.createLifecycleProvider(this);

@Override
public void onResume() {
super.onResume();
myObservable
.compose(provider.bindToLifecycle())
.subscribe();
}
}
```

## Unsubscription

RxLifecycle does not actually unsubscribe the sequence. Instead it terminates the sequence. The way in which
Expand All @@ -94,7 +112,7 @@ the `Subscription` yourself and call `unsubscribe()` when appropriate.

The rxlifecycle-kotlin module provides built-in extensions to the base RxJava types:

```java
```kotlin
myObservable
.bindToLifecycle(myView)
.subscribe { }
Expand All @@ -104,6 +122,16 @@ myObservable
.subscribe { }
```

There is an additional rxlifecycle-android-lifecycle-kotlin module to provider extensions to work
with `LivecycleOwner`'s.

```kotlin

myObservable
.bindToLifecycle(myLifecycleActivity, ON_STOP)
.subscribe { }
```

## Installation

```gradle
Expand All @@ -118,8 +146,14 @@ compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.0.1'
// If you want to use Navi for providers
compile 'com.trello.rxlifecycle2:rxlifecycle-navi:2.0.1'
// If you want to use Android Lifecycle for providers
compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle:2.0.1'
// If you want to use Kotlin syntax
compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.0.1'
// If you want to use Kotlin syntax with Android Lifecycle
compile 'com.trello.rxlifecycle2:rxlifecycle-android-kotlin:2.0.1'
```

## License
Expand Down
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0-rc1'
classpath 'com.android.tools.build:gradle:2.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$verKotlin"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$verKotlin"
classpath 'com.github.ben-manes:gradle-versions-plugin:0.14.0'
Expand All @@ -30,6 +30,7 @@ ext {
buildToolsVersion = '25'

supportLibVersion = '25.2.0'
lifecycleVersion = '1.0.0-alpha1'

sourceCompatibilityVersion = JavaVersion.VERSION_1_7
targetCompatibilityVersion = JavaVersion.VERSION_1_7
Expand All @@ -38,6 +39,8 @@ ext {
rxJava = 'io.reactivex.rxjava2:rxjava:2.0.6'
rxAndroid = 'io.reactivex.rxjava2:rxandroid:2.0.1'
navi = 'com.trello.navi2:navi:2.0'
lifecycle = "android.arch.lifecycle:runtime:$lifecycleVersion"
lifecycleProcessor = "android.arch.lifecycle:compiler:$lifecycleVersion"
kotlinStdlib = "org.jetbrains.kotlin:kotlin-stdlib:$verKotlin"
appCompat = "com.android.support:appcompat-v7:$supportLibVersion"
supportAnnotations = "com.android.support:support-annotations:$supportLibVersion"
Expand Down
1 change: 1 addition & 0 deletions rxlifecycle-android-lifecycle-kotlin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
26 changes: 26 additions & 0 deletions rxlifecycle-android-lifecycle-kotlin/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'kotlin-android'

android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion

defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
}
}

repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
}

dependencies {
compile kotlinStdlib
compile project(':rxlifecycle-android-lifecycle')
}

apply from: "$rootDir/gradle/artifacts.gradle"
apply from: "$rootDir/gradle/gradle-mvn-push.gradle"

4 changes: 4 additions & 0 deletions rxlifecycle-android-lifecycle-kotlin/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
POM_NAME=RxLifecycle-Andoird-Lifecycle-kotlin
POM_DESCRIPTION=RxLifecycle-Android-Lifecycle-kotlin
POM_ARTIFACT_ID=rxlifecycle-android-lifecycle-kotlin
POM_PACKAGING=aar
25 changes: 25 additions & 0 deletions rxlifecycle-android-lifecycle-kotlin/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /opt/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.tatarka.rxlifecycle_android_lifecycle_kotlin" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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.rxlifecycle2.android.lifecycle.kotlin

import android.arch.lifecycle.Lifecycle
import android.arch.lifecycle.LifecycleOwner
import com.trello.lifecycle2.android.lifecycle.AndroidLifecycle
import io.reactivex.*

fun <T> Observable<T>.bindToLifecycle(owner: LifecycleOwner): Observable<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindToLifecycle())

fun <T> Observable<T>.bindUntilEvent(owner: LifecycleOwner, event: Lifecycle.Event): Observable<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindUntilEvent(event))

fun <T> Flowable<T>.bindToLifecycle(owner: LifecycleOwner): Flowable<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindToLifecycle())

fun <T> Flowable<T>.bindUntilEvent(owner: LifecycleOwner, event: Lifecycle.Event): Flowable<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindUntilEvent(event))

fun <T> Single<T>.bindToLifecycle(owner: LifecycleOwner): Single<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindToLifecycle())

fun <T> Single<T>.bindUntilEvent(owner: LifecycleOwner, event: Lifecycle.Event): Single<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindUntilEvent(event))

fun <T> Maybe<T>.bindToLifecycle(owner: LifecycleOwner): Maybe<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindToLifecycle())

fun <T> Maybe<T>.bindUntilEvent(owner: LifecycleOwner, event: Lifecycle.Event): Maybe<T>
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindUntilEvent(event))

fun <T> Completable.bindToLifecycle(owner: LifecycleOwner): Completable
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindToLifecycle<Completable>())

fun <T> Completable.bindUntilEvent(owner: LifecycleOwner, event: Lifecycle.Event): Completable
= this.compose(AndroidLifecycle.createLifecycleProvider(owner).bindUntilEvent<Completable>(event))
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">rxlifecycle-android-lifecycle-kotlin</string>
</resources>
1 change: 1 addition & 0 deletions rxlifecycle-android-lifecycle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
32 changes: 32 additions & 0 deletions rxlifecycle-android-lifecycle/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'

android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion

defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
}
}

repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
}

dependencies {
compile project(':rxlifecycle')

compile rootProject.ext.rxAndroid
compile rootProject.ext.supportAnnotations
compile rootProject.ext.lifecycle
annotationProcessor rootProject.ext.lifecycleProcessor

testCompile rootProject.ext.junit
testCompile rootProject.ext.robolectric
}

apply from: "$rootDir/gradle/artifacts.gradle"
apply from: "$rootDir/gradle/gradle-mvn-push.gradle"

4 changes: 4 additions & 0 deletions rxlifecycle-android-lifecycle/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
POM_NAME=RxLifecycle-Android-Lifecycle
POM_DESCRIPTION=RxLifecycle-Android-Lifecycle
POM_ARTIFACT_ID=rxlifecycle-android-lifecycle
POM_PACKAGING=aar
2 changes: 2 additions & 0 deletions rxlifecycle-android-lifecycle/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<manifest package="com.trello.rxlifecycle2.android.lifecycle" />

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.trello.lifecycle2.android.lifecycle;

import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.OnLifecycleEvent;
import android.support.annotation.CheckResult;

import com.trello.rxlifecycle2.LifecycleProvider;
import com.trello.rxlifecycle2.LifecycleTransformer;
import com.trello.rxlifecycle2.RxLifecycle;

import javax.annotation.Nonnull;

import io.reactivex.Observable;
import io.reactivex.subjects.BehaviorSubject;

/**
* Wraps a {@link LifecycleOwner} so that it can be used as a {@link LifecycleProvider}. For example,
* you can do
* <pre>{@code
* LifecycleProvider<Lifecycle.Event> provider = AndroidLifecycle.createLifecycleProvider(this);
* myObservable
* .compose(provider.bindLifecycle())
* .subscribe();
* }</pre>
* where {@code this} is a {@link android.arch.lifecycle.LifecycleActivity} or {@link android.arch.lifecycle.LifecycleFragment}.
*/
public final class AndroidLifecycle implements LifecycleProvider<Lifecycle.Event>, LifecycleObserver {

public static LifecycleProvider<Lifecycle.Event> createLifecycleProvider(LifecycleOwner owner) {
return new AndroidLifecycle(owner);
}

private final BehaviorSubject<Lifecycle.Event> lifecycleSubject = BehaviorSubject.create();

private AndroidLifecycle(LifecycleOwner owner) {
owner.getLifecycle().addObserver(this);
}

@Nonnull
@Override
@CheckResult
public Observable<Lifecycle.Event> lifecycle() {
return lifecycleSubject.hide();
}

@Nonnull
@Override
@CheckResult
public <T> LifecycleTransformer<T> bindUntilEvent(@Nonnull Lifecycle.Event event) {
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
}

@Nonnull
@Override
@CheckResult
public <T> LifecycleTransformer<T> bindToLifecycle() {
return RxLifecycleAndroidLifecycle.bindLifecycle(lifecycleSubject);
}

@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void onEvent(LifecycleOwner owner, Lifecycle.Event event) {
lifecycleSubject.onNext(event);
if (event == Lifecycle.Event.ON_DESTROY) {
owner.getLifecycle().removeObserver(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.trello.lifecycle2.android.lifecycle;

import android.arch.lifecycle.Lifecycle;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;

import com.trello.rxlifecycle2.LifecycleTransformer;
import com.trello.rxlifecycle2.OutsideLifecycleException;

import io.reactivex.Observable;
import io.reactivex.functions.Function;

import static com.trello.rxlifecycle2.RxLifecycle.bind;

public final class RxLifecycleAndroidLifecycle {

private RxLifecycleAndroidLifecycle() {
throw new AssertionError("No instances");
}

/**
* Binds the given source to an Android lifecycle.
* <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 (ON_CREATE, ON_START, etc) it will choose the equivalent destructive phase (ON_DESTROY,
* ON_STOP, etc). If used in the destructive phase, the notifications will cease at the next event;
* for example, if used in ON_PAUSE, it will unsubscribe in ON_STOP.
*
* @param lifecycle the lifecycle sequence of an Activity
* @return a reusable {@link LifecycleTransformer} that unsubscribes the source during the Activity lifecycle
*/
@NonNull
@CheckResult
public static <T> LifecycleTransformer<T> bindLifecycle(@NonNull Observable<Lifecycle.Event> lifecycle) {
return bind(lifecycle, LIFECYCLE);
}

private static final Function<Lifecycle.Event, Lifecycle.Event> LIFECYCLE = new Function<Lifecycle.Event, Lifecycle.Event>() {
@Override
public Lifecycle.Event apply(Lifecycle.Event lastEvent) throws Exception {
switch (lastEvent) {
case ON_CREATE:
return Lifecycle.Event.ON_DESTROY;
case ON_START:
return Lifecycle.Event.ON_STOP;
case ON_RESUME:
return Lifecycle.Event.ON_PAUSE;
case ON_PAUSE:
return Lifecycle.Event.ON_STOP;
case ON_STOP:
return Lifecycle.Event.ON_DESTROY;
case ON_DESTROY:
throw new OutsideLifecycleException("Cannot bind to Activity lifecycle when outside of it.");
default:
throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented");
}
}
};
}
Loading

0 comments on commit 7b6a3ef

Please sign in to comment.