Code Monkey home page Code Monkey logo

rxlifecycle's Introduction

RxLifecycle

This library allows one to automatically complete sequences based on a second lifecycle stream.

This capability is useful in Android, where incomplete subscriptions can cause memory leaks.

Usage

You must start with an Observable<T> representing a lifecycle stream. Then you use RxLifecycle to bind a sequence to that lifecycle.

You can bind when the lifecycle emits anything:

myObservable
    .compose(RxLifecycle.bind(lifecycle))
    .subscribe();

Or you can bind to when a specific lifecyle event occurs:

myObservable
    .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
    .subscribe();

Alternatively, you can let RxLifecycle determine the appropriate time to end the sequence:

myObservable
    .compose(RxLifecycleAndroid.bindActivity(lifecycle))
    .subscribe();

It assumes you want to end the sequence in the opposing lifecycle event - e.g., if subscribing during START, it will terminate on STOP. If you subscribe after PAUSE, it will terminate at the next destruction event (e.g., PAUSE will terminate in STOP).

Providers

Where do lifecycles come from? Generally, they are provided by an appropriate LifecycleProvider<T>. But where are those implemented?

You have a few options for that:

  1. Use rxlifecycle-components and subclass the provided RxActivity, RxFragment, etc. classes.
  2. Use Android's lifecycle + rxlifecycle-android-lifecycle to generate providers.
  3. Write the implementation yourself.

If you use rxlifecycle-components, just extend the appropriate class, then use the built-in bindToLifecycle() (or bindUntilEvent()) methods:

public class MyActivity extends RxActivity {
    @Override
    public void onResume() {
        super.onResume();
        myObservable
            .compose(bindToLifecycle())
            .subscribe();
    }
}

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

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 it does so varies based on the type:

  • Observable, Flowable and Maybe - emits onCompleted()
  • Single and Completable - emits onError(CancellationException)

If a sequence requires the Subscription.unsubscribe() behavior, then it is suggested that you manually handle the Subscription yourself and call unsubscribe() when appropriate.

Kotlin

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

myObservable
    .bindToLifecycle(myView)
    .subscribe { }

myObservable
    .bindUntilEvent(myRxActivity, STOP)
    .subscribe { }

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

myObservable
    .bindUntilEvent(myLifecycleActivity, ON_STOP)
    .subscribe { }

Installation

implementation 'com.trello.rxlifecycle4:rxlifecycle:4.0.2'

// If you want to bind to Android-specific lifecycles
implementation 'com.trello.rxlifecycle4:rxlifecycle-android:4.0.2'

// If you want pre-written Activities and Fragments you can subclass as providers
implementation 'com.trello.rxlifecycle4:rxlifecycle-components:4.0.2'

// If you want pre-written support preference Fragments you can subclass as providers
implementation 'com.trello.rxlifecycle4:rxlifecycle-components-preference:4.0.2'

// If you want to use Android Lifecycle for providers
implementation 'com.trello.rxlifecycle4:rxlifecycle-android-lifecycle:4.0.2'

// If you want to use Kotlin syntax
implementation 'com.trello.rxlifecycle4:rxlifecycle-kotlin:4.0.2'

// If you want to use Kotlin syntax with Android Lifecycle
implementation 'com.trello.rxlifecycle4:rxlifecycle-android-lifecycle-kotlin:4.0.2'

License

Copyright (C) 2016 Trello

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.

rxlifecycle's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxlifecycle's Issues

java.lang.internalError with retrofit and proguard.

Hi.
Here is my environment

  1. Extended RxAppComatActivity
  2. Created two methods for composing
 public <T> Transformer<T, T> applyToMainThread() {
        return new Transformer() {
            public Observable<T> call(Observable<T> observable) {
                return observable.observeOn(AndroidSchedulers.mainThread());
            }
        };
    }

    public <T> Transformer<T, T> bindRxActivity(ActivityLifecycleProvider provider) {
        return provider.bindToLifecycle();
    }
  1. Calling a method in onCreate which creates an observable from Retrofit
  2. Calling applyToMainThread followed by bindRxActivity, in two chain calls of compose method.
  3. I have applied proguard on release build where I am discovering this crash
  java.lang.InternalError:22:12.233  13773-13809/? W/System.errjava.lang.InternalError
    at rx.internal.util.unsafe.UnsafeAccess.addressOf(SourceFile:103)
    at rx.internal.util.unsafe.MpmcArrayQueueProducerField.<clinit>(SourceFile:31)
    at rx.internal.util.ObjectPool.initialize(SourceFile:125)
    at rx.internal.util.ObjectPool.<init>(SourceFile:55)
    at rx.internal.util.ObjectPool.<init>(SourceFile:37)
    at rx.internal.util.RxRingBuffer$1.<init>(SourceFile:279)
    at rx.internal.util.RxRingBuffer.<clinit>(SourceFile:279)
    at rx.internal.operators.OnSubscribeCombineLatest.<init>(SourceFile:52)
    at rx.Observable.combineLatest(SourceFile:789)
    at rx.Observable.combineLatest(SourceFile:520)
    at com.trello.rxlifecycle.RxLifecycle$2.call(SourceFile:152)
    at com.trello.rxlifecycle.RxLifecycle$2.call(SourceFile:148)
    at rx.Observable.compose(SourceFile:204)
    at com.restaurant.zoomi.SplashScreen.getApplicationObject(SourceFile:131)
    at com.restaurant.zoomi.SplashScreen.onCreate(SourceFile:118)
    at android.app.Activity.performCreate(Activity.java:5990)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
    at android.app.ActivityThread.access$800(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5254)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    at java.lang.Class.getDeclaredField(Class.java:890)
    at rx.internal.util.unsafe.UnsafeAccess.addressOf(SourceFile:100)

SourceFile:152 points to following code.

private static <T, R> Transformer<T, T> bind(Observable<R> lifecycle, final Func1<R, R> correspondingEvents) {
        if(lifecycle == null) {
            throw new IllegalArgumentException("Lifecycle must be given");
        } else {
            final Observable sharedLifecycle = lifecycle.share();
            return new Transformer() {
                public Observable<T> call(Observable<T> source) {
                    return source.takeUntil(Observable.combineLatest(sharedLifecycle.take(1).map(correspondingEvents), sharedLifecycle.skip(1), new Func2() {
                        public Boolean call(R bindUntilEvent, R lifecycleEvent) {
                            return Boolean.valueOf(lifecycleEvent == bindUntilEvent);
                        }
                    }).takeFirst(new Func1() {
                        public Boolean call(Boolean shouldComplete) {
                            return shouldComplete;
                        }
                    }));
                }
            };
        }
    }

This code runs fine in debug build without obfuscation.
Is there anything done wrong w.r.t. proguard?

The latest version(0.3.1) cause a lot of type convert error while compiling

It works well in version 0.3.0.
Here is my code snippet:

 feedService.getTopicFeedList(groupId, loadPage)
            .compose(this.bindToLifecycle())
            .subscribe(
                feedDetails -> {
                    BannerFeedsAdapter adapter = (BannerFeedsAdapter) recyclerView.getAdapter();
                    if (adapter == null) {
                        adapter = new BannerFeedsAdapter(BannerFeedsActivity.this, feedDetails, bannerUrl, isContainBanner);
                        recyclerView.setAdapter(adapter);
                    } else {
                        adapter.append(feedDetails);
                        adapter.notifyDataSetChanged();
                    }
                    bannerImg.setVisibility(View.GONE);
                },
                throwable -> RxUtil.handleError(throwable, BannerFeedsActivity.this)
            );

The type of feedDetails is Object when I use the 0.3.1 version library.

min API 14 requirement?

…/src/main/AndroidManifest.xml Error:
    uses-sdk:minSdkVersion 10 cannot be smaller than version 14 declared in library [com.trello:rxlifecycle:0.3.0] …/build/intermediates/exploded-aar/com.trello/rxlifecycle/0.3.0/AndroidManifest.xml
    Suggestion: use tools:overrideLibrary="com.trello.rxlifecycle" to force usage

Is there a real reason for this limitation?

Support for ListFragments

We use some ListFragments in our apps and it would be nice to have an Rx component that we can extend in these cases. It appears to be a quick addition so I can make a PR with this support if that makes sense. Thanks!

Lifecycle support

Are there any plans to implement Android lifecycle support (recreating over rotation)? I've seen some workarounds in the Internet, but afaiu it is some kind of the DIY LoaderManager approach. Maybe I would make pull request, if I have enough time and it is interesting to somebody but me.

Should there be an ActivityEvent.ON_SAVE_INSTANCE_STATE?

We are running into an issue where there are some things that cannot occur after onSaveInstanceState is called (e.g. fragment transactions) and we want to make sure that the Rx chain is unsubscribed at that point, but the activity lifecycle methods do not cover that. Pause is close but there is no guaranteed order between onPause and onSaveInstanceState which still leaves a possibility of an error.

onComplete being called onDestroy

Hi, I got some weird behavior with retrofit Observables when used together with RxLifecycle.
I am not quite sure, but by this documentation[1] the default behavior of Observables is to don't call onComplete if onError is fired, but the onComplete method is being called in onDestroy of Actvity/Fragment.
Is this the right thing to do?
In the code below I can get the openHomeScreen() to be called. Should I move it to onNext()?

mUserApiClient
                .get()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .compose(RxLifecycle.bindFragment(lifecycle()))
                .subscribe(
                        new Subscriber<User>() {
                            @Override
                            public void onCompleted() {
                                openHomeScreen();
                            }

                            @Override
                            public void onError(Throwable e) {
                                handleRequestError(e);
                            }

                            @Override
                            public void onNext(User user) {
                                mUserManager.setUser(user);
                            }
                        });
    }

[1] http://reactivex.io/documentation/observable.html

Make bindUntilEvent() and bind() public?

These methods are actually generic enough that they can be reused for other lifecycles (such as controllers in MVP patterns). Would be nice to use them rather than copying in logic and mixing in activity and controller lifecycles.

Specify API 23 requirement?

I ran into issues building against Android level 22. Issue went away targeting API 23. Not sure if I just missed it in the documentation or if it's worth adding to the README?

Type inference problems

With 0.3.1 Android Studio 1.5 started having problems inferring the types when using compose.

composing with rxlifecycle bindings causes compiler error

If I compose using rxlifecycle, the compiler seems to throw errors. If I leave out the composition, the compiler is fine.

error:

Error:(55, 45) error: no suitable method found for subscribe(Subscriber<TestModel>)
method Observable.subscribe(Action1<? super Object>) is not applicable
(argument mismatch; Subscriber<TestModel> cannot be converted to Action1<? super Object>)
method Observable.subscribe(Observer<? super Object>) is not applicable
(argument mismatch; Subscriber<TestModel> cannot be converted to Observer<? super Object>)
method Observable.subscribe(Subscriber<? super Object>) is not applicable
(argument mismatch; Subscriber<TestModel> cannot be converted to Subscriber<? super Object>)
method Observable.<T>subscribe(Subscriber<? super T>,Observable<T>) is not applicable
(cannot infer type-variable(s) T
(actual and formal argument lists differ in length))
where T is a type-variable:
T extends Object declared in method <T>subscribe(Subscriber<? super T>,Observable<T>)

relevant objects:

PublishSubject<TestModel> pubTest = PublishSubject.create();
Subscriber<TestModel> testNotify = new Subscriber<TestModel>() {...};
protected void onResume() {
        super.onResume();
        pubTest.compose(bindToLifecycle()).subscribe(testNotify);
    }

Add support for rx.Single

Single is the alternate version of Observable and should be supported to automatically unsubscribe based on Lifecycle events as well.

Make RxBinding dependency optional

The RxBinding library contains over 600 methods. That's about five times the total number of methods in the RxLifecycle base + components libraries. It's unfortunate that this library pulls in that many extra methods, especially when it appears that library is only used for one line of code.

Would it be possible to split out the RxBinding-related functionality into an optional module?

Using bindView (and possibly other bindings) with an Observable subscribed on an async scheduler

bindView sets up its detach listener in its OnSubscribe call, which is nicer than the pre-1.x RxAndroid ViewObservable.bindView since it doesn't immediately set up the listener, even if not yet subscribed.

However, that means if I try to do (assume I'm calling this from the main thread):

getNetworkThing()
    .subscribeOn(Schedulers.io())
    .compose(RxLifecycle.bindView(fooView))
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(putThingOnViewFn);

it will blow up in RxBinding in its onSubscribe since it is being called off the main thread. One workaround is to defer, like:

Observable.defer(() -> getNetworkThing().subscribeOn(Schedulers.io())) 
    .compose(...)
    ...

but this is clunky at best. I'm not sure we would want a hard dependency on RxAndroid and its main scheduler (I sometimes use a wrapped main thread scheduler that can run things immediately if already on the main thread anyway), but maybe we could have overloads in RxLifecycle that allow you to optionally pass in a subscribeOn scheduler for the detach stream?

source.takeUntil(RxView.detaches(view).subscribeOn(scheduler))

seems like it would solve the problem, since the detach stream itself would subscribe on the passed in ui thread scheduler

Possible bug in "bindUntilFragmentEvent(lifecycle(), event)"

Hello there,

I started using the library after migrating from the old AppObservable. I experienced some weird crash (very sporadic) due to code being executed after the fragment view was destroyed. Then i tried to tie my tasks to PAUSE events and most of them went away but once in a while i experienced the same behavior.

After some digging and debugging my code i started to realize it is something related with this or the core library (not sure which one yet).

I discovered that sometimes you get the immediately subsequent event after the desired "STOP" FragmentEvent. Ex: If i want to receive events till onPause is called, sometimes i get an event immediately after onPause was sucessfully completed.

For this reason please consider this very basic fragment code

public class BauFragment extends RxFragment {
  PublishSubject<Integer> publishSubject = PublishSubject.create();

  public BauFragment() {
    lifecycle().subscribe(
        fragmentEvent -> {
          Timber.d("Fragment event is: %s - Thread: %s", fragmentEvent, Thread.currentThread());
        }
    );
  }

  @Override
  public void onPause() {
    Timber.d("onPause before super");
    super.onPause();
    Timber.d("onPause after super");
  }

  @Override
  public void onResume() {
    super.onResume();

    publishSubject
        .compose(RxLifecycle.bindUntilFragmentEvent(lifecycle(), FragmentEvent.PAUSE))
        .observeOn(AndroidSchedulers.mainThread())
        .subscribeOn(Schedulers.io())
        .subscribe(
            integer -> {

              Timber.d("Received %d, isResumed: %s, isRemoving: %s, thread: %s", integer, isResumed(), isRemoving(), Thread.currentThread());
            }
        );
    new Handler() {
      @Override
      public void handleMessage(Message msg) {
        publishSubject.onNext(msg.what);
        sendEmptyMessageDelayed(msg.what+1, 10);
      }
    }.sendEmptyMessage(1);
  }
}

It should look pretty straightforward. I'm trying to publish an integer through the publishSubject every 10ms ( bug appears also with 50ms or 100ms but is more sporadic ).

The generated output (depending how much time you let the fragment running before hitting the back button) should look similar to the following. (Note it does not always happen - as I said with 10ms you've more chances to get see it)

08-14 23:21:39.846 D/BauFragment﹕ Fragment event is: ATTACH - Thread: Thread[main,5,main]
08-14 23:21:39.847 D/BauFragment﹕ Fragment event is: CREATE - Thread: Thread[main,5,main]
08-14 23:21:39.848 D/BauFragment﹕ Fragment event is: START - Thread: Thread[main,5,main]
08-14 23:21:39.848 D/BauFragment﹕ Fragment event is: RESUME - Thread: Thread[main,5,main]
08-14 23:21:39.968 D/BauFragment﹕ Received 1, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.010 D/BauFragment﹕ Received 2, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.018 D/BauFragment﹕ Received 3, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.027 D/BauFragment﹕ Received 4, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.039 D/BauFragment﹕ Received 5, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.049 D/BauFragment﹕ Received 6, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.060 D/BauFragment﹕ Received 7, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.069 D/BauFragment﹕ Received 8, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.080 D/BauFragment﹕ Received 9, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
[--- Removed for clarity ---]
08-14 23:21:40.750 D/BauFragment﹕ Received 75, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.760 D/BauFragment﹕ Received 76, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.770 D/BauFragment﹕ Received 77, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.780 D/BauFragment﹕ Received 78, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.791 D/BauFragment﹕ Received 79, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.801 D/BauFragment﹕ Received 80, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:40.810 D/BauFragment﹕ Received 81, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:41.130 D/BauFragment﹕ Received 82, isResumed: true, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:41.194 D/BauFragment﹕ onPause before super
08-14 23:21:41.194 D/BauFragment﹕ Fragment event is: PAUSE - Thread: Thread[main,5,main]
08-14 23:21:41.194 D/BauFragment﹕ onPause after super
08-14 23:21:41.199 D/BauFragment﹕ Received 83, isResumed: false, isRemoving: false, thread: Thread[main,5,main]
08-14 23:21:41.565 D/BauFragment﹕ Fragment event is: STOP - Thread: Thread[main,5,main]
08-14 23:21:41.570 D/BauFragment﹕ Fragment event is: DESTROY_VIEW - Thread: Thread[main,5,main]
08-14 23:21:41.570 D/BauFragment﹕ Fragment event is: DESTROY - Thread: Thread[main,5,main]
08-14 23:21:41.571 D/BauFragment﹕ Fragment event is: DETACH - Thread: Thread[main,5,main]

Besides the headaches that this caused to me, it may be a "severe" bug if you bind to DESTROY_VIEW and, as I happened to see, sometimes an event goes through to the subscriber after onDestroyView gets called -> you'll likely to get a nullpointerexception (especially if you use Butterknife.unbind())

Before you ask these are my dependencies.

    // Rxjava stuff
    compile 'io.reactivex:rxjava:1.0.14'
    compile 'io.reactivex:rxandroid:1.0.1'
    compile 'com.trello:rxlifecycle:0.1.0'
    compile 'com.trello:rxlifecycle-components:0.1.0'
    compile 'com.jakewharton.rxbinding:rxbinding:0.1.0'

Min SDK 15?

I'd like to know why the minSDK for these libraries is 15. Seems restrictive. If I force override on my project (min 14), should I expect some things to break?

NoSuchFieldException: producerIndex

Since I updated from v0.1.0 to v0.2.0 I get this error. I think it is a proguard problem.

I found this producerIndex field in rx.internal.util.unsafe.SpscArrayQueueProducerFields and in rx.internal.util.unsafe.SpmcArrayQueueProducerField

This line -keep class rx.internal.util.unsafe.** { *; } in my proguard conf fixes the problem.

Maybe you want to add this info to the readme? :-)
I doesn't have this problem with RxAndroid or with RxBinding

How to extend the functionality?

I'd like to add the ability to receive events whenever onNewIntent() is called. How can this be done? Currently the event objects are enums (for example ActivityEvent) which can not be extended to include new objects.

SupportFragment?

Hi how cai I use RxFragment with Support v4?
I cannot find RxSupportFragment class :)

bindUntilEvent() on lifecycle() failes with 'ActivityEvent cannot be cast to rx.Observable'

I tried the following code, based on your Kotlin example from the readme.

class MainActivity: RxAppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        lifecycle()
        .bindUntilEvent(this, ActivityEvent.STOP)
        .subscribe({Log.d("Test", "Success")},{Log.e("Test", it.message, it)})
    }
}

I expected to see some "Success" log entries but got the following error.

Since my experience with RxJava and the RxLifecycle library is little, I am not sure whether my code is flawed or it is a bug.

E/Test: com.trello.rxlifecycle.ActivityEvent cannot be cast to rx.Observable
java.lang.ClassCastException: com.trello.rxlifecycle.ActivityEvent cannot be cast to rx.Observable
at com.trello.rxlifecycle.RxLifecycle$1.call(RxLifecycle.java:79)
at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54)
at rx.internal.operators.NotificationLite.accept(NotificationLite.java:150)
at rx.subjects.SubjectSubscriptionManager$SubjectObserver.accept(SubjectSubscriptionManager.java:318)
at rx.subjects.SubjectSubscriptionManager$SubjectObserver.emitLoop(SubjectSubscriptionManager.java:291)
at rx.subjects.SubjectSubscriptionManager$SubjectObserver.emitFirst(SubjectSubscriptionManager.java:270)
at rx.subjects.BehaviorSubject$1.call(BehaviorSubject.java:106)
at rx.subjects.BehaviorSubject$1.call(BehaviorSubject.java:102)
at rx.subjects.SubjectSubscriptionManager.add(SubjectSubscriptionManager.java:100)
at rx.subjects.SubjectSubscriptionManager.call(SubjectSubscriptionManager.java:60)
at rx.subjects.SubjectSubscriptionManager.call(SubjectSubscriptionManager.java:35)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable$2.call(Observable.java:162)
at rx.Observable$2.call(Observable.java:154)
at rx.Observable.subscribe(Observable.java:8191)
at rx.Observable.subscribe(Observable.java:8158)
at rx.Observable.subscribe(Observable.java:7962)
at ninja.mess.templateapplication.activity.MainActivity.onCreate(MainActivity.kt:28)
at android.app.Activity.performCreate(Activity.java:5990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: rx.exceptions.OnErrorThrowable$OnNextValue: OnError while emitting onNext value: CREATE
at rx.exceptions.Exceptions.throwOrReport(Exceptions.java:187)
at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:56)
at rx.internal.operators.NotificationLite.accept(NotificationLite.java:150) 
at rx.subjects.SubjectSubscriptionManager$SubjectObserver.accept(SubjectSubscriptionManager.java:318) 
at rx.subjects.SubjectSubscriptionManager$SubjectObserver.emitLoop(SubjectSubscriptionManager.java:291) 
at rx.subjects.SubjectSubscriptionManager$SubjectObserver.emitFirst(SubjectSubscriptionManager.java:270) 
at rx.subjects.BehaviorSubject$1.call(BehaviorSubject.java:106) 
at rx.subjects.BehaviorSubject$1.call(BehaviorSubject.java:102) 
at rx.subjects.SubjectSubscriptionManager.add(SubjectSubscriptionManager.java:100) 
at rx.subjects.SubjectSubscriptionManager.call(SubjectSubscriptionManager.java:60) 
at rx.subjects.SubjectSubscriptionManager.call(SubjectSubscriptionManager.java:35) 
at rx.Observable$2.call(Observable.java:162) 
at rx.Observable$2.call(Observable.java:154) 
at rx.Observable$2.call(Observable.java:162) 
at rx.Observable$2.call(Observable.java:154) 
at rx.Observable$2.call(Observable.java:162) 
at rx.Observable$2.call(Observable.java:154) 
at rx.Observable.subscribe(Observable.java:8191) 
at rx.Observable.subscribe(Observable.java:8158) 
at rx.Observable.subscribe(Observable.java:7962) 
at ninja.mess.templateapplication.activity.MainActivity.onCreate(MainActivity.kt:28) 
at android.app.Activity.performCreate(Activity.java:5990) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
at android.app.ActivityThread.access$800(ActivityThread.java:151) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5254) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372)

These are my dependencies:

compile 'com.android.support:appcompat-v7:23.2.1'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'com.trello:navi:0.2.0'
compile 'com.trello:rxlifecycle:0.5.0'
compile 'com.trello:rxlifecycle-components:0.5.0'
compile 'com.trello:rxlifecycle-navi:0.5.0'
compile 'com.trello:rxlifecycle-kotlin:0.5.0'

Failed to resolve: com.trello.rxlifecycle-kotlin:0.4.0

Hey,

Just saw the kotlin extension to this lib and wanted to give it a try. Unfortunatly I wasnt able to resolve it from either jCenter nor MavenCentral. I checked both manually and they contain every rxlifecycle package except the -kotlin one.

Did you forget to upload this?

Thanks,
danijoo

Espresso IdlingResource

I have a rather hard time to get RxJava in conjunction with RxLifecycle to play nicely during tests. I created a custom IdlingResource basically mimicking this prior art, but I see many, many subscriptions that are started, but never stopped, thus the idling resource never getting idle.

I realized that it may have something to do with RxLifecycle since it emits lifecycle events on a never-ending stream and indeed, when I remove my compose(bindToLifecycle()) calls, it kind of works. Now the interesting question is: Do you know of any way to detect (and ignore) subscriptions from RxLifecycle or is deactivating the bindToLifecycle() call in test mode altogether the only option?

wrong return types

RxLifecyle.bindUnitEvent returns return new Observable.Transformer<T, T>

But in the components classes your are returning

Observable.Transformer<? super T, ? extends T>

on bindUntilEvent and bindToLifecycle

SO which one folks? To haphazard a guess would it be the RxLifecycle ones are correct?

Push snapshot version to maven

Any chance the SNAPSHOT version of the library will be pushed to maven?
Since v. 0.3.0 is already released, maybe now it's time to bumb the version to 0.3.1-SNAPSHOT and push it to maven snapshot repository?

Upgrade to Fragment.onAttach(Context)

API 23 introduced Fragment.onAttach(Context) and deprecated Fragment.onAttach(Activity). We should look into using the newer version (while maintaining backwards compatibility).

How about View's lifecycle?

Could it possible to add simple View lifecycle support? e.g. onAttachedToWindow and onDetachedFromWindow.

use it with RxBinding or Retrofit,it always tips that the next line was wrong

RxTextView.textChanges(edt)
.compose(this.bindUntilEvent(ActivityEvent.PAUSE))
.doOnUnsubscribe(() -> Log.e("-->>", "doOnUnsubscribe"))
.debounce(600, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.filter(charSequence -> {
tv.setText("");
return charSequence.length() > 0;
})

Error: (61, 40) error: find no sign
Symbol: Method length ()
Location: type Object variable charSequence

Type Inference fails in Kotlin

When attempting to use RxLifecycle from Kotlin in an Observable chain the compiler cannot infer types in some cases unless explicitly specified.

Consider if I have a variable tasks of type Observable<List>

If I try to use that in an observable chain:

tasks.compose(RxLifecycle.bindView(taskList)) // followed by other clauses

The compiler complains that it cannot infer the type unless I explicitly specify it as in:

tasks.compose(RxLifecycle.bindView<List<Task>>(taskList)) // followed by other clauses

I think the problem is that you are not explicitly bounding the generic type to match the compose method. You have the method returning

Transformer<T, T>

And I think that should really be:

Transformer<? super T, ? extends T>

to match the semantics of the Observable.compose method.

I tested by writing a wrapper method that uses the latter return type and it fixes the type inference.

Why BehaviorSubject and not PublishSubject OR "Problems with fragment in backstack"

Good day, fellow colleagues! )

We had an issue with this approach your library describes.

Imagine there is a FragmentA and FragmentB. Both subscribe to some Observable in afterCreateView() callback (this is our safety-callback after onCreateView()). Using RxLifecycle we bound this subscription until onDestroyView() callback.

Next: we show FragmentA (got our subscription bound and ready for any incoming signals), then we use Android's FragmentManager to navigate to FragmentB - using replace, but leaving FragmentA in backstack so we can easily navigate "back". During navigating FragmentManager detaches FragmentA instance and the last lifecycle event we (and, therefore, our BehavoirSubject lifecycleSubject) get is FragmentEvent.DESTROY_VIEW.

FragmentB also subscribes to our Observable and bounds to lifecycle - nothing to do here, let's go back. Since FragmentA was navigated from with backstack enabled - it's instance is still there, and last lifecycle event that lifecycleSubject got was that FragmentEvent.DESTROY_VIEW - he still remembers it, since that is how BehaviorSubject works and he never died because FragmentA's instance is still alive.

Getting to the point: when we resurrect FragmentA instance (FragmentManager does that for us during "back" navigation) we - as before - bind our Observable to lifecycle and want to subscribe to it. But the first thing we get as soon as we bind - FragmentEvent.DESTROY_VIEW event, out subscription immediately receives onCompleted. Our FragmentA is not happy about this - no data update is possible for him from now on.

So far we've resolved this by switching to PublishSubject usage in our RxBaseFragment. But I fear there is something I might have forgotten about. Can you explain why BehaviorSubject was used in the first place? Is our workaround applicable (assuming that none of our programmers will try to bind to observable after onDestroyView() callback)?

P. S.: sorry, if my explanation is too broad - Rx approach is still tricky for me and I was at the same time trying to clear things up for myself with this issue.

bindToLifecycle() issue with subscribeOn(AndroidSchedulers.mainThread())

Hi, I'm using RxLifecycle in my project, it works well on most scenes, but when I using bindToLifecycle with subscribeOn(AndroidSchedulers.mainThread()), the Subscription#unsubscribe was called when the screen turns off.

I'm new to RxJava so I'm not sure whether it's a bug or not.

Below is the sample code:

        RxTextView.textChanges(mSearchEditor).compose(this.<CharSequence>bindToLifecycle()).doOnUnsubscribe(new Action0() {
            @Override
            public void call() {
                // called when the screen turns off.
                Log.d("test", "unsubscribe.");
            }
        }).subscribeOn(AndroidSchedulers.mainThread()).debounce(600, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
                .subscribe(new Action1<CharSequence>() {
                    @Override
                    public void call(CharSequence charSequence) {
                        Log.d("test", "s:" + charSequence);
                    }
                });

I'll be very grateful for your help.

Concurrency Issues: bindUntilEvent

I could notice in fragments when I transform an Observable with bindUntilEvent(FragmentEvent.DESTROY_VIEW) that onNext callback gets called after onDestroyView method returns. Since I use ButterKnife and call unbind in onDestroyView I am getting NullPointerException when my onNext implementation try to access views. This behaviour does not happen all the time. Seems to be a concurrency issue. Any thoughts?

Relax targetSdkVersion dependency

Currently this requires SDK version 23, which is very restrictive when trying to support "older" builds of Android. Dropping this to at least 22 would allow use in Android 5 and below.

Experiment w/ ActivityLifecycleCallbacks

Previously we avoided this route so that we could remain consistent between Activities and Fragments, but perhaps it's worth optimizing the Activity route (especially since some people just avoid Fragments altogether).

The idea is you could call bindUntilEvent(Activity, Event) and bindToLifecycle(Activity) instead of the current methods. We would then register an ActivityLifecycleCallbacks with the Application of the Activity which can provide us a lifecycle Observable.

Some questions about implementation...

  • Would we create a new ActivityLifecycleCallbacks every time, or would we store a global one (or maybe one per Activity)?
  • When would we unregister? Obviously we would always do so in onDestroy(), but perhaps this could be optimized (for example if you're only waiting for onPause). Generally speaking, how does the Subscriber communicate that it no longer needs the callbacks?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.