RX java2-AndroidSchedulers.mainThread

问题描述

Helllo,

getInfo()服务调用由多个片段同时订阅,所以我只想调用一次服务,存储该信息并返回。

我通过使用blockingGet()找到了解决方

 adddisposable(getInfoUseCase().get()
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(info -> {},throwable -> {}));

最终翻译为:

    private var info: InfoEntity? = null
    
        override fun getInfo(): Single<InfoEntity> {
            return if (info== null) {
            Single.just(service.getInfo(SERVICE_GET_INFO).blockingGet())
                .map { mapper.transform(it) }
                .doOnSuccess {
                    info = it
                }
        } else {
            return Single.just(info)
        }
    }

这是服务对象:

   Retrofit restAdapter = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(createClient(TIMEOUT,true))
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
                .build();

        service = restAdapter.create(RetrofitService.class);


@GET(".")
    Single<ApiResponse<InfoEntity>> getInfo(
            @Query(SERVICE_ID) String serviceId
    );

乍看之下,一切正常,但后来我找到了这个答案:

never use observeOn(AndroidSchedulers.mainThread()) with blockingGet()

但就我而言,一切正常,我没有什么区别,我的方法是否有问题?如果是这样,那有什么出路?

解决方法

问题是您正在阻塞主线程。这意味着当您等待网络通话时(可能需要5秒钟),UI将被完全冻结,并且用户将无法执行任何操作。这真的不是一个很棒的用户体验。

此修复程序很棘手。 BehaviorSubject在这里很有用,因为它允许在网络调用获取期间订阅的所有片段都接收结果通知。

// I assume these variables are in a singleton? Otherwise they won't be much use
private var subject: BehaviorSubject<InfoEntity> = BehaviorSubject.create()
var isFetching = false

override fun getInfo(): Single<InfoEntity> {

    // If the network call previously failed,reset the subject to a new empty one,so that this subscriber and future ones can receive a value
    if (subject.hasThrowable() || subject.hasComplete()) {
        subject = BehaviorSubject.create()
    }

    if (!subject.hasValue() && !isFetching) {
        isFetching = true
        fetch()
    }

    return subject.firstOrError()
}

private fun fetch() {
    fetchInfo()
            .doFinally {
                isFetching = false
            }
            .subscribe(
                    {
                        subject.onNext(it)
                    },{
                        subject.onError(it)
                    })
}