Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Thumbs.db
################
*~
*.swp
local.properties

# Gradle Files #
################
Expand Down
9 changes: 6 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
buildscript {
repositories { jcenter() }
dependencies { classpath 'com.netflix.nebula:gradle-rxjava-project-plugin:1.12.+' }

dependencies { classpath 'com.netflix.nebula:gradle-rxjava-project-plugin:1.12.+'
classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:1.12.+'
}
}

apply plugin: 'rxjava-project'

apply plugin: 'provided-base'

dependencies {
compile 'io.reactivex:rxjava:1.0.+'
provided 'com.google.android:android:4.0.1.2'
provided 'com.google.android:android:4.1.1.4'
provided 'com.google.android:support-v4:r7'

// testing
Expand Down
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
86 changes: 53 additions & 33 deletions src/main/java/rx/android/observables/AndroidObservable.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,6 @@

public final class AndroidObservable {

private static final boolean USES_SUPPORT_FRAGMENTS;

static {
boolean supportFragmentsAvailable = false;
try {
Class.forName("android.support.v4.app.Fragment");
supportFragmentsAvailable = true;
} catch (ClassNotFoundException e) {
}
USES_SUPPORT_FRAGMENTS = supportFragmentsAvailable;
}

private static final Func1<Activity, Boolean> ACTIVITY_VALIDATOR = new Func1<Activity, Boolean>() {
@Override
Expand Down Expand Up @@ -105,8 +94,33 @@ public static <T> Observable<T> fromActivity(Activity activity, Observable<T> so
* fragment while it's in detached state (i.e. its host Activity was destroyed.) In other words, during calls
* to onNext, you may assume that fragment.getActivity() will never return null.
* <p/>
* This method accepts both native fragments and support library fragments in its first parameter. It will throw
* for unsupported types.
* You must unsubscribe from the returned observable in <code>onDestroy</code> to not leak the given fragment.
* <p/>
* Ex.:
* <pre>
* // in any Fragment
* mSubscription = fromFragment(this, Observable.just("value")).subscribe(...);
* // in onDestroy
* mSubscription.unsubscribe();
* </pre>
*
* @param fragment the fragment in which the source observable will be observed
* @param sourceObservable the observable sequence to observe from the given fragment
* @param <T>
* @return a new observable sequence that will emit notifications on the main UI thread
* @deprecated Use {@link #bindFragment(android.support.v4.app.Fragment, rx.Observable)} instead
*/
@Deprecated
public static <T> Observable<T> fromFragment(android.support.v4.app.Fragment fragment, Observable<T> sourceObservable) {
Assertions.assertUiThread();
return OperatorObserveFromAndroidComponent.observeFromAndroidComponent(sourceObservable, fragment);
}

/**
* Transforms a source observable to be attached to the given fragment, in such a way that notifications will always
* arrive on the main UI thread. Moreover, it will be guaranteed that no notifications will be delivered to the
* fragment while it's in detached state (i.e. its host Activity was destroyed.) In other words, during calls
* to onNext, you may assume that fragment.getActivity() will never return null.
* <p/>
* You must unsubscribe from the returned observable in <code>onDestroy</code> to not leak the given fragment.
* <p/>
Expand All @@ -122,18 +136,12 @@ public static <T> Observable<T> fromActivity(Activity activity, Observable<T> so
* @param sourceObservable the observable sequence to observe from the given fragment
* @param <T>
* @return a new observable sequence that will emit notifications on the main UI thread
* @deprecated Use {@link #bindFragment(Object, rx.Observable)} instead
* @deprecated Use {@link #bindFragment(android.app.Fragment, rx.Observable)} instead
*/
@Deprecated
public static <T> Observable<T> fromFragment(Object fragment, Observable<T> sourceObservable) {
public static <T> Observable<T> fromFragment(Fragment fragment, Observable<T> sourceObservable) {
Assertions.assertUiThread();
if (USES_SUPPORT_FRAGMENTS && fragment instanceof android.support.v4.app.Fragment) {
return OperatorObserveFromAndroidComponent.observeFromAndroidComponent(sourceObservable, (android.support.v4.app.Fragment) fragment);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && fragment instanceof Fragment) {
return OperatorObserveFromAndroidComponent.observeFromAndroidComponent(sourceObservable, (Fragment) fragment);
} else {
throw new IllegalArgumentException("Target fragment is neither a native nor support library Fragment");
}
return OperatorObserveFromAndroidComponent.observeFromAndroidComponent(sourceObservable, fragment);
}

/**
Expand All @@ -156,7 +164,7 @@ public static <T> Observable<T> bindActivity(Activity activity, Observable<T> so
}

/**
* Binds the given source sequence to a fragment (native or support-v4).
* Binds the given source sequence to a support-v4 fragment.
* <p/>
* This helper will schedule the given sequence to be observed on the main UI thread and ensure
* that no notifications will be forwarded to the fragment in case it gets detached from its
Expand All @@ -169,18 +177,30 @@ public static <T> Observable<T> bindActivity(Activity activity, Observable<T> so
* @param fragment the fragment to bind the source sequence to
* @param source the source sequence
*/
public static <T> Observable<T> bindFragment(Object fragment, Observable<T> source) {
public static <T> Observable<T> bindFragment(android.support.v4.app.Fragment fragment, Observable<T> source) {
Assertions.assertUiThread();
final Observable<T> o = source.observeOn(mainThread());
if (USES_SUPPORT_FRAGMENTS && fragment instanceof android.support.v4.app.Fragment) {
android.support.v4.app.Fragment f = (android.support.v4.app.Fragment) fragment;
return o.lift(new OperatorConditionalBinding<T, android.support.v4.app.Fragment>(f, FRAGMENTV4_VALIDATOR));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && fragment instanceof Fragment) {
Fragment f = (Fragment) fragment;
return o.lift(new OperatorConditionalBinding<T, Fragment>(f, FRAGMENT_VALIDATOR));
} else {
throw new IllegalArgumentException("Target fragment is neither a native nor support library Fragment");
}
return o.lift(new OperatorConditionalBinding<T, android.support.v4.app.Fragment>(fragment, FRAGMENTV4_VALIDATOR));
}

/**
* Binds the given source sequence to a native fragment.
* <p/>
* This helper will schedule the given sequence to be observed on the main UI thread and ensure
* that no notifications will be forwarded to the fragment in case it gets detached from its
* activity or the activity is scheduled to finish.
* <p/>
* You should unsubscribe from the returned Observable in onDestroy for normal fragments, or in onDestroyView
* for retained fragments, in order to not leak any references to the host activity or the fragment.
* Refer to the samples project for actual examples.
*
* @param fragment the fragment to bind the source sequence to
* @param source the source sequence
*/
public static <T> Observable<T> bindFragment(Fragment fragment, Observable<T> source) {
Assertions.assertUiThread();
final Observable<T> o = source.observeOn(mainThread());
return o.lift(new OperatorConditionalBinding<T, Fragment>(fragment, FRAGMENT_VALIDATOR));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,6 @@ public void itSupportsNativeFragments() {
verify(observer).onCompleted();
}

@Test(expected = IllegalArgumentException.class)
public void itThrowsIfObjectPassedIsNotAFragment() {
AndroidObservable.bindFragment("not a fragment", Observable.never());
}

@Test(expected = IllegalStateException.class)
public void itThrowsIfObserverCallsFromFragmentFromBackgroundThread() throws Throwable {
final Future<Object> future = Executors.newSingleThreadExecutor().submit(new Callable<Object>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public void setupMocks() {
}

// TODO needs to be fixed, see comments inline below
/*
@Ignore
public void itObservesTheSourceSequenceOnTheMainUIThread() {
final Observable<Integer> testObservable = Observable.from(1)
Expand Down Expand Up @@ -109,6 +110,7 @@ public void call(Integer i) {
// I was going to run it on NewThread then observeOn to AndroidThread and validate it jumped
// to the correct thread, but it doesn't do anything. Need to work with Android devs.
}
*/

@Test
public void itForwardsOnNextOnCompletedSequenceToTargetObserver() {
Expand Down