【问题标题】:Rx java2 - blockingGet() inside AndroidSchedulers.mainThread()Rx java2 - 在 AndroidSchedulers.mainThread() 中阻塞Get()
【发布时间】:2020-12-02 17:36:56
【问题描述】:

你好,

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

但就我而言,一切正常,我不明白有什么区别,我的方法有什么问题吗?如果有,有什么出路?

【问题讨论】:

    标签: android mvvm rx-java2


    【解决方案1】:

    问题是你阻塞了主线程。这意味着当您等待网络调用(可能需要 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)
                        })
    }
    

    【讨论】:

    • 在您的示例中,如果多个片段同时订阅,则会进行多个调用,因为在第一个下载信息之前,第二个将订阅并进行网络调用,我只想要一个网络调用,这就是为什么我用了blockingGet...
    • 给我几分钟,我会为你解决这个问题。你可能想要的是一个 BehaviourSubject
    • 嗯,这让事情变得更加困难,您必须考虑一些事情。如果第一次网络调用失败,你想发生什么?将错误提供给所有片段?每当有新片段订阅时重试?
    • 为片段提供错误,对我来说很好,是的,提供错误后,如果有新订阅,重试将是nesccecery :D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 2011-07-04
    相关资源
    最近更新 更多