Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could you pls provide some sample? #80

Closed
tianxm opened this issue Sep 7, 2017 · 8 comments
Closed

Could you pls provide some sample? #80

tianxm opened this issue Sep 7, 2017 · 8 comments

Comments

@tianxm
Copy link

tianxm commented Sep 7, 2017

Could you pls provide some sample? I still not very clear to use it from read me.

@ZacSweers
Copy link
Collaborator

ZacSweers commented Sep 7, 2017

What would you want to see in a sample?

Basically, for every RxJava type (Observable, Single, etc) there's a corresponding _____Scoper (ObservableScoper, SingleScoper, etc). Each scoper has three constructors that accept either a Maybe, ScopeProvider, or LifecycleScopeProvider.

Maybe is the core case, the other overloads just resolve back down to a Maybe under the hood.

ScopeProvider is an abstraction that allows non-rxjava types to provide their own scope.

LifecycleScopeProvider is something a bit more complex that allows you to have multiple lifecycle events and scope against their symmetric destruction events (aka create-destroy, start-stop, etc). Still an interface though, so you could define your own lifecycle (different architectures like Conductor, etc). I may pull this out to a separate component in the future though.

You simply use rxjava's to operator and give it a corresponding scoper instance. Since this is operating on observers (for disposable handling), the only thing you have left to call is subscribe, which scopers offer as a proxy in their APIs.

So something like this:

myStringObservable
    .to(new ObservableScoper<String>(myScope))
    .subscribe();

@djkovrik
Copy link

djkovrik commented Sep 8, 2017

What would you want to see in a sample?

What about just a simple Android app?
Readme inspecting does not make things more clear to be honest.

@tianxm
Copy link
Author

tianxm commented Sep 9, 2017

@hzsweers thank you for the answer, I am still not very clear, what's myScope in the code you give?

@ZacSweers
Copy link
Collaborator

@djkovrik

Would you like to contribute a sample in a PR? This is a java project first and foremost, so I hadn't really thought to add an android sample for fear of making people think it's just for android. If we just called it android-sample though then I think it's fine.

@tianxm

It can be whatever you want. Something that implements ScopeProvider or LifecycleScopeProvider (such as an activity in android, or some sort of worker abstraction), or you can just give it a Maybe instance (or use any of the coercing operators from other rxjava types, e.g. Observable.firstElement()).

@djkovrik
Copy link

djkovrik commented Sep 10, 2017

@hzsweers
I'm a newcomer and come here for samples too :) Thought that there is some easy way to bind disposal with Activity/Fragment lifecycle but just noticed that #36 and #37 discussions.
Made a quick try with Maybe which is seems to be just a small tip for @tianxm rather than good sample:

public class MainActivity extends AppCompatActivity {

    public static final String TAG = MainActivity.class.getSimpleName();

    private MaybeSubject<String> maybeScope = MaybeSubject.create();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate called");

        Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnDispose(new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.d(TAG, "Dispose called");
                    }
                })
                .to(new ObservableScoper<Long>(maybeScope))
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long count) throws Exception {
                        Log.d(TAG, "Started from onCreate, running: " + count);
                    }
                });
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause called (Observable is still running)");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy called (dispose should be called now)");
        maybeScope.onSuccess("Done");
    }
}

@ZacSweers
Copy link
Collaborator

Yep! That's a good simple example. You would likely further abstract this by pushing it into a BaseActivity of sorts and sending lifecycle events to a behavior relay, similar to how RxLifecycle works, then just filter on the target event and call .firstElement(), so something like this

enum ActivityEvent {
  CREATE, START, RESUME, PAUSE, STOP, DESTROY;
}

public class MainActivity extends AppCompatActivity {

    public static final String TAG = MainActivity.class.getSimpleName();

    private BehaviorSubject<ActivityEvent> lifecycle = BehaviorSubject.create();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        lifecycle.onNext(CREATE);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate called");

        Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnDispose(new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.d(TAG, "Dispose called");
                    }
                })
                .to(new ObservableScoper<Long>(lifecycle.filter(e -> e == DESTROY).firstElement()))
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long count) throws Exception {
                        Log.d(TAG, "Started from onCreate, running: " + count);
                    }
                });
    }

    @Override
    protected void onStart() {
        super.onStart();
        lifecycle.onNext(START);
    }

    @Override
    protected void onResume() {
        super.onResume();
        lifecycle.onNext(RESUME);
    }

    @Override
    protected void onPause() {
        super.onPause();
        lifecycle.onNext(PAUSE);
        Log.d(TAG, "onPause called (Observable is still running)");
    }

    @Override
    protected void onStop() {
        super.onStop();
        lifecycle.onNext(STOP);
    }

    @Override
    protected void onDestroy() {
        lifecycle.onNext(DESTROY);
        super.onDestroy();
        Log.d(TAG, "onDestroy called (dispose should be called now)");
    }
}

You can wrap that up into nice helper methods like:

protected Maybe<?> until(ActivityEvent event) {
    return lifecycle.filter(e -> e == event).firstElement();
}

// then your activity subclasses could do this
someObservable
    .to(new ObservableScoper(until(DESTROY)))

Or you could use the RxLifecycle-style automatic symmetry with LifecycleScopeProvider, which will automatically bind to the corresponding destruction event. This can be a bit too magical though and works best if you just have symmetric attach/detach events. It does have the added benefit of giving you lifecycle boundary checks though (aka not before/after lifecycle starts/ends).

public class MainActivity extends AppCompatActivity implements LifecycleScopeProvider<ActivityEvent> {

    private static final Function<ActivityEvent, ActivityEvent> CORRESPONDING_EVENTS =
      new Function<ActivityEvent, ActivityEvent>() {
        @Override public ActivityEvent apply(ActivityEvent lastEvent) throws Exception {
          switch (lastEvent) {
            case CREATE:
              return DESTROY;
            case START:
              return STOP;
            case RESUME:
              return PAUSE;
            case PAUSE:
            case STOP:
              return DESTROY;
            case DESTROY:
              throw new OutsideLifecycleException("Activity is already destroyed!");
          }
        }
      };

    public static final String TAG = MainActivity.class.getSimpleName();

    private BehaviorSubject<ActivityEvent> lifecycle = BehaviorSubject.create();

    @Override
    public Observable<ActivityEvent> lifecycle() {
        return lifecycle.hide();
    }

    @Override
    public ActivityEvent peekLifecycle() {
        return lifecycle.getValue();
    }

    @Override 
    public Function<ActivityEvent, ActivityEvent> correspondingEvents() {
      return CORRESPONDING_EVENTS;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        lifecycle.onNext(CREATE);
        setContentView(R.layout.activity_main);

        Log.d(TAG, "onCreate called");

        Observable.interval(1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnDispose(new Action() {
                    @Override
                    public void run() throws Exception {
                        Log.d(TAG, "Dispose called");
                    }
                })
                .to(new ObservableScoper<Long>(this))  // The important part
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long count) throws Exception {
                        Log.d(TAG, "Started from onCreate, running: " + count);
                    }
                });
    }

    @Override
    protected void onStart() {
        super.onStart();
        lifecycle.onNext(START);
    }

    @Override
    protected void onResume() {
        super.onResume();
        lifecycle.onNext(RESUME);
    }

    @Override
    protected void onPause() {
        super.onPause();
        lifecycle.onNext(PAUSE);
        Log.d(TAG, "onPause called (Observable is still running)");
    }

    @Override
    protected void onStop() {
        super.onStop();
        lifecycle.onNext(STOP);
    }

    @Override
    protected void onDestroy() {
        lifecycle.onNext(DESTROY);
        super.onDestroy();
        Log.d(TAG, "onDestroy called (dispose should be called now)");
    }
}

@tianxm
Copy link
Author

tianxm commented Sep 11, 2017

@hzsweers @djkovrik thx for the sample, I think it will help me a lot.

@tianxm tianxm closed this as completed Sep 11, 2017
@djkovrik
Copy link

@hzsweers Now that's a good sample 👍 Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants