【问题标题】:Obtaining reference to original Scheduler获取对原始调度器的引用
【发布时间】:2016-01-27 16:23:17
【问题描述】:

我有以下 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() 等)李>

在我看来,实现此目的的伪代码如下所示:

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();

这可能吗?

【问题讨论】:

  • 保留原Scheduler的引用,以后再用?
  • 感谢您的意见!如果链都是内联构造的,这将是可行的,如上面的简化示例中所示;但是,原始问题的以下警告:“(尽管应该注意,在我的实际应用程序中,链接分布在几种不同的方法中)”意味着 subscribeOn 的调用远离使用 @ 的 flatmap 987654336@。这意味着理想情况下,我希望有一个更“本地化”的解决方案,其中两个 observeOn 包装表示 flatmap 不需要知道原始的 Scheduler 类型。
  • (在呼叫站点定义)。

标签: java android rx-java rx-android


【解决方案1】:

来自observeOn() documentation:

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

正如 Aaron He 所提到的,您可以保留一些对您正在使用的调度程序的引用,在后者“observeOn”上使用它。


我有时使用的另一种方法是删除“observeOn”函数,并确保 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();
                    }
                });  
            }
        });
    }

【讨论】:

  • 好主意!我回复了前者作为对原始问题的评论。关于后者:我很好奇,当您使用这种模式时,您通常是在Runnable 内调用订阅者方法(例如subscriber.onNext),还是直接在call 方法内调用?我想在Runnable 内调用是我想在这里尝试的。
  • 这取决于我需要执行的操作。我只在需要更新 UI 时使用Runnable。因此,例如,如果在我完成更新后我想调用onNext,它将进入Runnable。但是通常情况并非如此,我直接从call 方法调用它。
猜你喜欢
  • 1970-01-01
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
  • 2013-06-11
  • 2021-12-08
  • 1970-01-01
相关资源
最近更新 更多