Giter Site home page Giter Site logo

uber / autodispose Goto Github PK

View Code? Open in Web Editor NEW
3.4K 66.0 234.0 12.26 MB

Automatic binding+disposal of RxJava streams.

Home Page: https://uber.github.io/AutoDispose/

License: Apache License 2.0

Shell 0.23% Java 74.07% Kotlin 25.70%
uber autodispose rxjava reactive-extensions reactive-streams rxandroid android kotlin lifecycle

autodispose's People

Contributors

0legg avatar ajalt avatar akarnokd avatar alexfu avatar atexannamedbob avatar bangarharshit avatar carldea avatar charlesdurham avatar danh32 avatar dependabot[bot] avatar fr373969 avatar friederbluemle avatar hoeggi avatar lsvijay avatar lukestclair avatar markyc avatar mmallozzi avatar msridhar avatar mswysocki avatar psteiger avatar rafaeltoledo avatar rajin9601 avatar rubengees avatar sanggggg avatar shaishavgandhi avatar tonycosentini avatar tonytangandroid avatar tyvsmith avatar visheshvadhera avatar zacsweers avatar

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

autodispose's Issues

LifecycleEndException handling

Specifically, some might want to just dispose quietly (in production, or always) rather than error. Should we make this more configurable? If so, how/to what degree? Moving this discussion here from an internal one.

Currently - LifecycleEndException is propagated to the delegate observer's onError. I see two options:

A. If the delegate doesn't implement onError, it goes to RxJavaPlugins and one could filter that in a plugin hook. This would not cover cases where onError is implemented though. Is this fine?
B. We make this more explicitly configurable

  • Scoper overloads?
  • RxJavaPlugins-esque plugin system?
  • Nothing, advise just writing a custom ScopeProvider implementation using ScopeUtils?

CC @tonycosentini @AttwellBrian

Explore making error handling more configurable

One major benefit to this approach is that while on RxJava 1 we (internally) threw hard exceptions on lifecycle boundary issues, I think we can actually safely swallow them now since disposal means no terminal events will be emitted.

Why not before?

Before, we couldn't really safely swallow these for two reasons:

  • Had to complete immediately to still abide by the Observable contract
  • That terminal event bubbled down, and could still trigger any number of events that we didn't want.

Why configurable vs. just always dispose silently?

At the end of the day, this is still (probably) programmer error that we want to catch. Configurability should allow for enabling these checks in, say, debug builds.

Other thoughts:

  • What should the default behavior? Error or silent? I vote silent

Removing synthetic accessors

There is around 27 synthetic accessors method (most of which are in tests). RecordingObserver, AutoDisposingSubscriberImpl (and similar classes) has around 12 methods. Maybe convert them to package protected to reduce dex count by 12.

Add DialogScopeProvider module

Add DialogScopeProvider module

public enum DialogLifecycleEvent {
    SHOW, CANCLE, DISMISS
}

or just

public enum DialogLifecycleEvent {
    SHOW, DISMISS
}

Scope chain naming

Using withScope() currently is feeling weird, especially when some scope providers are just other classes (e.g. views) . Wanted to put up a couple others for thought:

  • scopeWith
  • scope
  • scopeTo

@uber/mobile-platform-android what do you think?

Tune API to type().scope().around() style

Per internal discussion, for explicitness we are opting to go with something like this:

subscribe(AutoDispose.maybe().scopeTo(provider).around(...))

Also LifecycleProvider -> ScopeProvider

Possible extra exploration: Only expose interfaces for the intermediaries with private implementations.

Discussion/proposal: Allow for consumer code gen to generate first party APIs

Glide 4.0 has some really cool ideas around allowing consumers to code gen their own APIs into the first party API. Iโ€™ve been thinking - what if we tried to do something like this in AutoDispose to allow developers to promote their own first party APIs while making the core APIs available for use (basically Maybe + ScopeProvider). This is a bit more left field, but I think it would be a nice evolution and support the myriad.

Details on how this would work are still fuzzy and Iโ€™ll need to think on it more, but want to toss it up for consideration.

  • Things that are/could be modules that could be generated into the first party APIs include
    • ViewScopeProvider
    • LifecycleOwnerScopeProvider (#71) for arch components
    • LifecycleScopeProvider
      • This could be nice as it's a controversial approach.
    • Static factories (#61), for those that prefer them
      • If we do this, should the _____Scoper methods be optional?
    • (currently nonexistent) RxViewHolder? ConductorLifecycle? ______?
    • (crazy idea) ScopeProvider itself!

CC @tonycosentini @jbarr21

AndroidLifecycleScopeProvider do not work

I tried the AndroidLifecycleScopeProvider implementation with the following code, but it doesn't work and keep emitting when onStop()` is called.

override fun onStart() {
    super.onStart()
    Observable.interval(0, 1, TimeUnit.SECONDS)
      .doOnDispose { println("dispose") }
      .to(ObservableScoper(AndroidLifecycleScopeProvider.from(this)))
      .subscribe {
        println("emit:" + it)
      }
  }

  override fun onStop() {
    super.onStop()
    println("onStop")
  }

Thanks.

Review of RxJava 2 usage in the project

Hi. I was asked to review the library's RxJava 2 usage for potential logical or concurrency issues.

Review @ commit: 0147484b

Main issues:

  • AutoDisposingCompletableObserverImpl.java#L45: The DisposableMaybeObserver could be created and setOnce'd before the call to lifecycle.subscribe().
  • AutoDisposingCompletableObserverImpl.java#L52: The mainDisposable could be already set and the delegate currently executing one of its onXXX methods which violates the contract unless it is guaranteed both the lifecycle signal and the onXXX calls happen on the same thread (i.e., forced observeOn(AndroidSchedulers.mainThread())). Possible solution: always call delegate.onSubscribe(this) first, mutually exclude the onXXX signals via an AtomicBoolean once.
  • AutoDisposingCompletableObserverImpl.java#L58: May not be a good idea to leave the delegate non-terminated in this case, if the lifecycle actually can get onComplete.
  • AutoDisposingCompletableObserverImpl.java#L73: synchronized is pointless here.
  • AutoDisposingCompletableObserverImpl.java#L80: synchronized is pointless here. If the purpose was to mutually exclude with #L73 then it is not worth it. If lazySet wins then dispose(ref) will do nothing, if they race, both cases could win probabilistically.
  • AutoDisposingMaybeObserverImpl.java: Same problems as with the CompletableObserver implementation.
  • AutoDisposingObserverImpl.java: Same problems as with the CompletableObserver implementation. Here one would need a HalfSerializer to mutually exclude the onXXX events (as there could be multiple onNext calls).
  • AutoDisposingSingleObserverImpl.java: Same problems as with the CompletableObserver implementation.
  • AutoDisposingSubscriberImpl.java: Same problems as with the CompletableObserver implementation and then some.
  • AutoDisposingSubscriberImpl.java#L80: There is no onStart provided by the API and the delegate.onSubscribe is called after mainSubscription is definitely set: the null check should always pass and thus unnecessary. Note though that if one does the setOnce(mainSubscription) before the lifecycle is attached, one may need to use deferred requesting to not trigger the upstream emission while the code is setting up other things in onSubscribe.
  • ViewAttachEventsObservable.java#L41 If the call is not on the main thread, onSubscribe is not called which can lead to a NullPointerException in the dowstream. The no-op Disposable should be sent to the Observer first.
  • ViewAttachEventsObservable.java#L51: The Observer may cancel immediately and since the listener is not registered with the view yet, it won't get removed but then added unconditionally. Assuming the events also come from the main thread, one could add the listener first, and call onSubscribe next. If adding the listener triggers an event emission immediately, keep the current order and after adding the listener, check if the listener has been disposed in the meantime and remove the listener.
  • LifecycleEventsObservable.java#L78: Same problems as with the ViewAttachEventsObservable.

Minor issues:

Re-enable android tests on CI

After a bit of experimentation in #79 and travis-ci/travis-ci#8360, the new trusty setup on travis CI's public/oss use is not getting the avdmanager on the PATH for some reason. In light of that, I'm going to disable the android tests in travis CI in #79 (and will link this in a comment above it).

Until it's fixed, we'll just have to manually check android checks before merging PRs.

Release notes for 0.5.0

WIP notes for changelog when we release, which should be soooooonish

New converter-based API for use with as() (#141)

AutoDispose's primary API is now via static autoDisposable() methods on the AutoDispose class. The previous to() based APIs are now completely deprecated, and will be removed in AutoDispose 1.0.

This has been sort of the long-standing ideal API for AutoDispose for awhile, but wasn't possible until the introduction of the new as() operator in RxJava. As this operator is still not marked as stable (and won't until RxJava 2.2.0), AutoDispose will not be updated to 1.0 until then.

The main difference is that you no longer have to specify the type indirection, and the returned converter is applicable for all 5 RxJava types. In use, it looks like this:

Flowable.just(1)
    .as(autoDisposable(scope))
    .subscribe()

Observable.just(1)
    .as(autoDisposable(scope))
    .subscribe()

Maybe.just(1)
    .as(autoDisposable(scope))
    .subscribe()

Single.just(1)
    .as(autoDisposable(scope))
    .subscribe()

Completable.complete()
    .as(autoDisposable(scope))
    .subscribe()

There are three overloads for autoDisposable(), for each of the three scope types (Maybe, ScopeProvider, and LifecycleScopeProvider).

The Kotlin bindings have also been updated to match semantics, with the autoDisposeWith extension functions being deprecated in favor of analogous autoDisposable. These are WARNING level in this release, and will become ERROR in AutoDispose 0.6.0, before finally being removed in 1.0. They also provide replaceWith options (compatible with Kotlin's deprecation quickfixes).

autoDisposable reads best when statically imported (so you can do .as(autoDisposable(...)), which you can safely do if you're using Java 8.

TODO Provide structural replaces.

Fixed a lot of concurrency edge cases and performance improvements after review from David Karnok (#138 and #130)

David Karnok (@akarnokd, RxJava project lead) did an audit of the current codebase and gave extensive feedback in #130. #138 implements that feedback. This handled a lot of concurrency gotchas and edge cases we were missing before. See the issue and PR for full details.

Plugin for controlling whether or not to fill in stacktraces (#124)

AutoDisposePlugins has a new API to control whether or not lifecycle exception stacktraces are filled in. What this means is that if you opt out, the exceptions thrown in LifecycleScopeProvider boundary issues will no longer have a stacktrace (getStacktrace() will return an empty array) and only carry the type name and message. This can be useful to gain some performance if you track stacktracing via other means.

UNBOUND shorthand (#125)

ScopeProvider has a static instance of an "unbound" provider directly in the interface now for reuse. This obviates the need for TestScopeProvider#unbound(), which has been removed. Usage is simple:

Observable.just(1)
    .as(autoDisposable(ScopeProvider.UNBOUND))
    .subscribe()

Misc

  • Archcomponents updated to 1.0.0 final (#128)
  • RxJava dependency is now 2.1.7 (to leverage as()) (#141)
  • Kotlin is now updated to 1.2.0 (#141)
  • Dokka is wired up, meaning that javadocs found at now have kotlin docs too. (#126)
  • subscribeBy example extension in the sample app displaying how you can add extension functions to the *SubscribeProxy classes. (#127)
  • delegateObserver() APIs on AutoDisposing observers have been promoted to stable. Considering they are useful for subscribeWith(), we can just keep it observer-based and keep the library more flexible long-term (#144)

Thanks to the following contributors! @charlesdurham @ajalt @tbsandee @akarnokd

Expose observable source for ObservableSubscribeProxy

fun <T : Any> Observable<T>.mySubscribe(f: () -> Unit): Disposable {
  return doOnSubscribe { f() }
    .subscribe(Consumer {}, Consumer {})
}

With .to(ObservableScoper(AndroidLifecycleScopeProvider.from(this))), we can't take advantage of kotlin's extension to use my custom mySubscribe method since it is a ObservableSubscribeProxy type.

Do you think it is better to expose the observable source for ObservableSubscribeProxy?

Prepare for 0.2.0

  • New: Kotlin artifact! (#47)

This adds autoDisposeWith() extensions to RxJava types.

myObservable
   .doWhatever()
   .autoDisposeWith(this)
   .subscribe()
  • New: Plugin system! (#57)

Modeled after RxJava's plugins, this allows you to customize the behavior of AutoDispose with lifecycle boundary checks.

AutoDisposePlugins.setOutsideLifecycleHandler(t -> {
    // Swallow the exception, or rethrow it, or throw your own!
})

A good use case of this is, say, just silently disposing/logging observers outside of lifecycle exceptions in production but crashing on debug.

  • New: Test helpers! (#48 #49)

Two helpers were added to simulate conditions in testing.

  • TestLifecycleScopeProvider
    • This has two corresponding lifecycle methods: start() and stop()
  • TestScopeProvider
    • Has just one method - emit().

For testing with just the Maybe<?> scope, we recommend using RxJava's built-in MaybeSubject.

  • Fix: Fixed a race condition where upstream wouldn't be disposed if the lifecycle emitted or error'd synchronously (i.e. was already terminated). (#57)
  • Fix: Add missing @CheckReturnValue annotations to subscribeWith methods. (#53)

Other tidbits:

  • Removed @NonNull annotations. Everything is @NonNull by default, and only elements
    annotated with @Nullable are not.
  • Use of the new java-library plugin for gradle (#64). The RxJava dependencies are marked as api.
  • Error prone has been integrated. Currently the annotations are just marked as compileOnly, but if a need arises/community wants them - we can compile them in a future version.

Measuring runtime performance

If I add .to(new ObservableScoper<RequestLocation>(lifecycle)) to an observable it makes it noticeably slower. Not super slow: just 0.13ms on a pixel (I put this in a loop with 500 iterations and measured the increase in duration). But slower than using a simple composite disposable pattern.

Some thoughts from a chat with Zac below

The exec path under the hood when you do this (this point when you call to()):

  • create new Scoper
  • scoper implements subscribeproxy

(this point on happens when you call subscribe())

  • calling subscribe creates an autodisposing observable, which is just a normal observable that has a custom observer in subscribeActual
  • the custom observer implements AutoDisposingObserver, creates an extra subscription on the lifecycle
  • all pub sub from there

potential areas of wins:

  • don't use consumers for lifecycle subscription to avoid unnecessary rxjava LambdaObserver creation
  • Maybe LifecycleScopeProvider could be lazier, but I doubt it. It already defer()'s to subscribe()-time, but if you want boundary checks there then you have to do it synchronously

Question: Are AndroidLifecycleScopeProvider instances intended to be reusable?

This is for AutoDispose 0.3.0.

A pattern I used for my custom scope providers for fragments/activities against AutoDispose 0.2.0 was to create a single scope provider (based on BehaviorSubject) and then share it between all observable chains for that entity. This worked fine, I think.

Now I'm migrating to the new AndroidLifecycleScopeProvider and I find that if I create a single instance for a fragment or activity, when, for example, a second onStart event occurs I get the exception below.

If I recreate the AndroidLifecycleScopeProvider instance for each subscription then it works fine, but it feels like it could be excess overhead. I do notice that this is the pattern you use in the samples, so perhaps it's intentional. There's no indication in AndroidLifecycleScopeProvider that it's stateful, so I'm just checking.

io.reactivex.exceptions.OnErrorNotImplementedException: Lifecycle has ended!
                         E      at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:704)
                         E      at io.reactivex.internal.functions.Functions$OnErrorMissingConsumer.accept(Functions.java:701)
                         E      at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:77)
                         E      at com.uber.autodispose.AutoDisposingObserverImpl.onError(AutoDisposingObserverImpl.java:102)
                         E      at com.uber.autodispose.AutoDisposingObserverImpl$2.accept(AutoDisposingObserverImpl.java:57)
                         E      at com.uber.autodispose.AutoDisposingObserverImpl$2.accept(AutoDisposingObserverImpl.java:55)
                         E      at io.reactivex.internal.operators.maybe.MaybeCallbackObserver.onError(MaybeCallbackObserver.java:83)
                         E      at io.reactivex.internal.operators.maybe.MaybeDoOnEvent$DoOnEventMaybeObserver.onError(MaybeDoOnEvent.java:100)
                         E      at io.reactivex.internal.disposables.EmptyDisposable.error(EmptyDisposable.java:83)
                         E      at io.reactivex.internal.operators.maybe.MaybeDefer.subscribeActual(MaybeDefer.java:44)
                         E      at io.reactivex.Maybe.subscribe(Maybe.java:3727)
                         E      at io.reactivex.internal.operators.maybe.MaybeDoOnEvent.subscribeActual(MaybeDoOnEvent.java:39)
                         E      at io.reactivex.Maybe.subscribe(Maybe.java:3727)
                         E      at io.reactivex.Maybe.subscribeWith(Maybe.java:3793)
                         E      at io.reactivex.Maybe.subscribe(Maybe.java:3714)
                         E      at io.reactivex.Maybe.subscribe(Maybe.java:3680)
                         E      at com.uber.autodispose.AutoDisposingObserverImpl.onSubscribe(AutoDisposingObserverImpl.java:51)
                         E      at io.reactivex.internal.observers.BasicFuseableObserver.onSubscribe(BasicFuseableObserver.java:66)
                         E      at io.reactivex.internal.observers.BasicFuseableObserver.onSubscribe(BasicFuseableObserver.java:66)
                         E      at com.jakewharton.rxrelay2.PublishRelay.subscribeActual(PublishRelay.java:68)
                         E      at io.reactivex.Observable.subscribe(Observable.java:10910)
                         E      at io.reactivex.internal.operators.observable.ObservableFilter.subscribeActual(ObservableFilter.java:30)
                         E      at io.reactivex.Observable.subscribe(Observable.java:10910)
                         E      at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:33)
                         E      at io.reactivex.Observable.subscribe(Observable.java:10910)
                         E      at com.uber.autodispose.ObservableScoper$AutoDisposeObservable.subscribeActual(ObservableScoper.java:113)
                         E      at io.reactivex.Observable.subscribe(Observable.java:10910)
                         E      at io.reactivex.Observable.subscribe(Observable.java:10896)
                         E      at io.reactivex.Observable.subscribe(Observable.java:10799)
                         E      at com.uber.autodispose.ObservableScoper$1.subscribe(ObservableScoper.java:71)
                         E      at com.orangebikelabs.BrowseFragment.onStart(BrowseFragment.java:222)
                         E      at android.support.v4.app.Fragment.performStart(Fragment.java:2380)
                         E      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1458)
                         E      at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1740)
                         E      at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1809)
                         E      at android.support.v4.app.BackStackRecord.executePopOps(BackStackRecord.java:857)
                         E      at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2577)
                         E      at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2367)
                         E      at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2322)
                         E      at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2229)
                         E      at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:700)
                         E      at android.os.Handler.handleCallback(Handler.java:751)
                         E      at android.os.Handler.dispatchMessage(Handler.java:95)
                         E      at android.os.Looper.loop(Looper.java:154)
                         E      at android.app.ActivityThread.main(ActivityThread.java:6120)
                         E      at java.lang.reflect.Method.invoke(Native Method)
                         E      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                         E      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
                         E  Caused by: com.uber.autodispose.LifecycleEndedException: Lifecycle has ended!
                         E      at com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider$1.apply(AndroidLifecycleScopeProvider.java:52)
                         E      at com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider$1.apply(AndroidLifecycleScopeProvider.java:38)
                         E      at com.uber.autodispose.ScopeUtil$3.call(ScopeUtil.java:91)
                         E      at com.uber.autodispose.ScopeUtil$3.call(ScopeUtil.java:74)
                         E      at io.reactivex.internal.operators.maybe.MaybeDefer.subscribeActual(MaybeDefer.java:41)
                         E      ... 39 more

Should we return a custom observer type to indicate disposability?

Ran into a case where an old RxJava method returned a Subscription bound to a lifecycle. We could leverage subscribeWith to do the same, but currently around() methods just return simple Observers and don't indicate that they're disposable. We can't make all the observers extend RxJava's available Disposable_______Observers, so we'd have to make our own. Question is if we want to do this in the API, like returning an AutoDisposeObserver that implements Disposable.

@uber/mobile-platform-android thoughts?

Fill in README

Mostly we can use what was detailed in the internal RFC.

Other things:

  • License footer
  • Maven coordinates
  • Little icon?
  • Travis build badge?
  • License badge?

Compatibility with android.arch.lifecycle 1.0.0-rc1

Looks like AutoDispose 0.3.0 is compatible only with android.arch.lifecycle 1.0.0-beta1 and the move to rc1 is not backwards compatible:

java.lang.ClassCastException: com.uber.autodispose.android.lifecycle.LifecycleEventsObservable_ArchLifecycleObserver_LifecycleAdapter cannot be cast to android.arch.lifecycle.GeneratedAdapter

This is probably fixed by the bump to use rc1 in PR #111.

This issue can serve as a sentry until that PR Is committed and a new version is released.

bindUntilEvent with architecture components

Version: 0.3.0

I was previously using RxLifecycle and played around a bit with AutoDispose. So far it works great, but i miss the bindUntilEvent method from RxLifecycle.
I have seen the other issue about this, but could not manage to get it to work, especially when using architecture components integration...
Some samples or even better, a first class api would be very appreciated.

My current RxLifecycle code looks like this:

errorButton.clicks()
    .bindUntilEvent(this, Lifecycle.Event.ON_DESTROY)
    .subscribe {
        // Do something.
     }

Thanks in advance!

Observer type entry point

As I'm implementing more with AutoDispose, the type specification is getting annoying. With the changes I made in #17 though (the clauses pattern in particular), it actually is fairly trivial to pull these out to just individual classes. E.g.

  • AutoDisposeObserver
  • AutoDisposeSingleObserver
  • AutoDisposeMaybeObserver

etc

So the API becomes as follows:

myObservable.subscribe(AutoDisposeObserver
    .withScope(...)
    .around(...)

Trying this out briefly, it does save precious seconds while not blowing up autocomplete (if anything, saves autocomplete time since you can pick the type right there in the IDE). Cons are that refactoring to a different type is harder, and we sacrifice the convenience of a single point of entry.

@uber/mobile-platform-android what do you think?

Add a test module.

Ideally, it should be easy to create ScopeProvider and LifecycleScopeProvider instances for testing.

They should:

  • Discourage mocking (mocking LifecycleScopeProvider is particularly fragile).
  • Make it simple to vend out test instances that are easy to start/stop.

Use Git Versioning

Right now the only version I can see is X.Y.Z. (Which does not exist on maven). It would be great if you could tag releases.

Proposal: More structured android components

Currently have -android and -android-archcomponents

Wondering if we should move these under a /android directory and do the following

  • Provide kotlin components of existing ones with extension functions (View.scope() rather than ViewScopeProvider.from(view))
  • Provide ready-to-use android components like AutoDisposeActivity or AutoDisposeViewHolder
  • Possibly separate out the TestAndroidLifecycle to its own artifact so the main archcomponents artifact only have a runtime dependency

Release notes for 0.4.0

WIP notes for changelog when we release, which should be soooooonish

Structured Android Components (#111)

Android components have been split up into several artifacts under :android:

  • autodispose-android: Core android utilities, previously :autodispose-android
  • autodispose-android-archcomponents: Utilities for lifecycles in android archcomponents, previously :autodispose-android-archcomponents but does not have the test helper
  • New: autodispose-android-archcomponents-test: Test utilities for working with arch components, namely TestLifecycleOwner, formerly TestAndroidLifecycleScopeProvider.
    • This allows us to remove the extensions dependency from the main arch components artifact and keep this optional. This API can also be used for general use testing for arch components, as it's not actually specific to AutoDispose.
  • New: autodispose-android-kotlin: kotlin bindings for autodispose-android
  • New: autodispose-android-archcomponents-kotlin: kotlin bindings for autodispose-android-archcomponents
  • New: autodispose-android-archcomponents-test-kotlin: kotlin bindings for autodispose-android-test-archcomponents
  • New: Android artifacts include consumer proguard rules (relates to #112)

Related changes:

  • Fix: Arch components updated to 1.0.0-rc1, which should fix compatibility issues noted in #113
  • Enhancement: untilEvent overload for AndroidLifecycleScopeProvider (#107)
    • Now you can bind until a specific target event, or provide your own boundary provider function
  • Behavior change: previously, anything occurring after ON_STOP would resolve to ON_DESTROY. Now, they resolve to stop on the next destruction event. This brings it inline with the modern behavior of arch components version -rc1.
  • Enhancement: AndroidLifecycleScopeProviders are now reusable. This is somewhat experimental, as it works by dynamically resolving the last event based on the state. Please report any issues! (#121)

RxLifecycle Interop

A new autodispose-rxlifecycle interop module was added, adding support for scoping to RxLifecycle's LifecycleProvider API. (#118)

Misc

  • Reduced object allocations (#108)
  • Convenience unbound() factory on TestScopeProvider (#108)
  • Removed synthetic accessors (#103)
  • Updated to Kotlin 1.1.51 (#116)

Thanks to the following contributors! @rubengees @bangarharshit

API Change Discussion: Switch to Single instead of Maybe

This is something I think might be an inherent design flaw in AutoDispose currently. Maybe was used before under the idea that scopes could potentially not emit. However, it's left us in an awkward case where they could either emit or complete, which is different. Furthermore, it's actually not dangerous to depend on a single because in the event of termination of the source stream, it would just dispose the single it was waiting on.

This is a pretty significant API change. Fortunately I think it would be mitigated by the fact that most people use ScopeProvider and LifecycleScopeProvider + hopefully the test helpers.

RxLifecycle interop module

Should we add one? The gist would be that it could understand RxLifecycle's LifecycleProvider mechanics, which in turn should also lend support for its various components (RxActivity, etc)

Proposal: Plugin point to make fillInStacktrace() configurable for lifecycle boundary exceptions

Exceptions aren't free. Currently we use exceptions to indicate lifecycle boundaries. Normally their trace would be helpful, but in some setups (such as our internal one), users track sources of exceptions in rx chains separately and just use the exception as a signal. Perhaps we can save a little performance by making a plugin hook to configure this. Then when receiving exceptions, traces would not be inspectable and the type would be your only clue.

This would be possible for pre-java8 too by overriding fillInStacktrace() and controlling behavior there. The default would be to remain enabled.

public class OutsideLifecycleException extends RuntimeException {

  public OutsideLifecycleException(String s) {
    super(s);
  }

  @Override public final synchronized Throwable fillInStackTrace() {
    if (AutoDisposePlugins.fillInStacktraces()) {
      return super.fillInStackTrace();
    } else {
      return this;
    }
  }
}

Questions:

  • Should we?
  • If no, why not?
  • If yes
    • fillInStacktraces() method?
    • Static volatile boolean? (might not play well with lockdown())

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.