获取对原始Scheduler的引用

时间:2016-01-27 16:23:17

标签: java android rx-java rx-android

我有以下RxJava Observable

final class MapBitmapObservable {

    static Observable<Bitmap> create(@NonNull final MapView mapView) {
        return Observable.create(new Observable.OnSubscribe<Bitmap>() {
            @Override
            public void call(final Subscriber<? super Bitmap> subscriber) {
                mapView.getMapAsync(new OnMapReadyCallback() {
                    @Override
                    public void onMapReady(@NonNull final GoogleMap googleMap) {
                        googleMap.snapshot(new GoogleMap.SnapshotReadyCallback() {
                            @Override
                            public void onSnapshotReady(@Nullable final Bitmap bitmap) {
                                if (bitmap != null) {
                                    subscriber.onNext(bitmap);
                                    subscriber.onCompleted();
                                } else {
                                    subscriber.onError(new MapSnapshotFailedException());
                                }
                            }
                        });
                    }
                });
            }
        });
    }

    private MapBitmapObservable() {

    }

}

必须在主线程上调用MapView方法getMapAsync以避免此异常:

java.lang.IllegalStateException: getMapAsync() must be called on the main thread
    at com.google.android.gms.common.internal.zzx.zzcD(Unknown Source)
    at com.google.android.gms.maps.MapView.getMapAsync(Unknown Source)
    at com.github.stkent.bugshaker.email.screenshot.maps.MapBitmapObservable$1.call(MapBitmapObservable.java:42)
    at com.github.stkent.bugshaker.email.screenshot.maps.MapBitmapObservable$1.call(MapBitmapObservable.java:37)
    at rx.Observable.unsafeSubscribe(Observable.java:8098)
    ...

假设MapBitmapObservable被用作Observable链的一部分,其中前一个和后一个操作可能长时间运行并且应该在主线程之外执行。简化示例可能如下所示:

Observable.just(activity)
        .flatmap(new Func1<Activity, Observable<MapView>>() {
            @Override
            public Observable<Bitmap> call(@NonNull final Activity activity) {
                return ExpensiveToCreateObservable.create(activity);
            }
        })
        .flatmap(new Func1<MapView, Observable<Bitmap>>() {
            @Override
            public Observable<Bitmap> call(@NonNull final MapView mapView) {
                return MapBitmapObservable.create(mapView);
            }
        })
        .flatmap(new Func1<Bitmap, Observable<Uri>>() {
            @Override
            public Observable<Uri> call(@NonNull final Bitmap bitmap) {
                return SomeOtherExpensiveToCreateObservable.create(bitmap);
            }
        })
        .subscribeOn(Schedulers.io())
        .subscribe();

(尽管应该注意的是,在我的实际应用中,链接分布在几种不同的方法中)。我想:

  1. 确保在主线程上调用MapView.getMapAsync;
  2. 允许第二个长时间运行的操作在原始调度程序上执行,可能是Schedulers.io()Schedulers.computation()等等。)
  3. 在我看来,实现这一点的伪代码看起来像是:

    Observable.just(activity)
            .flatmap(new Func1<Activity, Observable<MapView>>() {
                @Override
                public Observable<Bitmap> call(@NonNull final Activity activity) {
                    return ExpensiveToCreateObservable.create(activity);
                }
            })
            .observeOn(AndroidSchedulers.mainThread()) // This is real, and resolves bullet 1.
            .flatmap(new Func1<MapView, Observable<Bitmap>>() {
                @Override
                public Observable<Bitmap> call(@NonNull final MapView mapView) {
                    return MapBitmapObservable.create(mapView);
                }
            })
            .observeOn(/* Some way of referencing the thread on which I originally subscribed, to resolve bullet 2. */)
            .flatmap(new Func1<Bitmap, Observable<Uri>>() {
                @Override
                public Observable<Uri> call(@NonNull final Bitmap bitmap) {
                    return SomeOtherExpensiveToCreateObservable.create(bitmap);
                }
            })
            .subscribeOn(Schedulers.io()) // I do not want to rely on knowledge of the Scheduler type used at this call-site. 
            .subscribe();
    

    这可能吗?

1 个答案:

答案 0 :(得分:1)

来自observeOn() documentation:

  另一方面,

ObserveOn会影响Observable将在该运算符出现的位置使用的线程。因此,您可以在Observable运算符链中的不同点多次调用ObserveOn,以便更改某些运算符在哪些线程上运行。

正如Aaron He所提到的,你可以保留一些你正在使用的调度程序的引用,在后者上使用它&#34; observeOn&#34;。

我有时会使用的另一种做法是删除&#34; observeOn&#34;函数,并确保Activity.runOnUiThread正在UI线程上处理View项目。像 -

这样的东西
static Observable<Bitmap> create(@NonNull final Activity activity,@NonNull final SomeObject someObject) {
        return Observable.create(new Observable.OnSubscribe<Pair<Activity,SomeObject>>() {
            @Override
            public void call(final Subscriber<? super Pair<Activity,SomeObject>> subscriber) {
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        someObject.doStuff();
                    }
                });  
            }
        });
    }