web-dev-qa-db-fra.com

RxJava2 UndeliverableException lorsqu'un changement d'orientation se produit lors de la récupération des données

J'obtiens l'erreur suivante, si je change l'orientation de mon appareil pendant que mon application récupère de nouveaux redditNews.

  E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-1
    Process: com.spicywdev.schmeddit, PID: 26522
    io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | null
        at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.Java:367)
        at io.reactivex.internal.operators.observable.ObservableCreate$CreateEmitter.onError(ObservableCreate.Java:73)
        at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.Java:43)
        at io.reactivex.Observable.subscribe(Observable.Java:12090)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.Java:96)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.Java:578)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.Java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.Java:57)
        at Java.util.concurrent.FutureTask.run(FutureTask.Java:237)
        at Java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.Java:272)
        at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1133)
        at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:607)
        at Java.lang.Thread.run(Thread.Java:762)
     Caused by: Java.io.InterruptedIOException
        at okhttp3.internal.http2.Http2Stream.waitForIo(Http2Stream.Java:579)
        at okhttp3.internal.http2.Http2Stream.takeResponseHeaders(Http2Stream.Java:143)
        at okhttp3.internal.http2.Http2Codec.readResponseHeaders(Http2Codec.Java:125)
        at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.Java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:147)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.Java:45)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.Java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.Java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.Java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.Java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.Java:200)
        at okhttp3.RealCall.execute(RealCall.Java:77)
        at retrofit2.OkHttpCall.execute(OkHttpCall.Java:180)
        at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.Java:91)
        at com.spicywdev.schmeddit.features.news.NewsManager$getNews$1.subscribe(NewsManager.kt:16)
        at io.reactivex.internal.operators.observable.ObservableCreate.subscribeActual(ObservableCreate.Java:40)

Voilà à quoi ressemble la classe. Une erreur se produit dans la fonction requestNews().

class NewsFragment : RxBaseFragment() {

    companion object {
        private val KEY_REDDIT_NEWS = "redditNews"
    }

    private var redditNews: RedditNews? = null
    private val newsManager by lazy { NewsManager() }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return container?.inflate(R.layout.news_fragment)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        news_list.apply {
            setHasFixedSize(true)
            val linearLayoutManager = LinearLayoutManager(context)
            layoutManager = linearLayoutManager
            clearOnScrollListeners()
            addOnScrollListener(InfiniteScrollListener({ requestNews()}, linearLayoutManager))
        }

        initAdapter()

        if (savedInstanceState != null && savedInstanceState.containsKey(KEY_REDDIT_NEWS)) {
            redditNews = savedInstanceState.get(KEY_REDDIT_NEWS) as RedditNews
            (news_list.adapter as NewsAdapter).clearAndAddNews(redditNews!!.news)
        } else {
            requestNews()
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        val news = (news_list.adapter as NewsAdapter).getNews()
        if (redditNews != null && news.isNotEmpty()) {
            outState.putParcelable(KEY_REDDIT_NEWS, redditNews?.copy(news = news))
        }
    }

    private fun requestNews() {
        /**
         * first time will send empty string for after parameter.
         * Next time we will have redditNews set with the next page to
         * navigate with the after param.
         */
        val subscription = newsManager.getNews(redditNews?.after ?: "")
            .subscribeOn(Schedulers.io())
            .subscribe(
                {
                    retrievedNews ->
                    redditNews = retrievedNews
                    (news_list.adapter as NewsAdapter).addNews(retrievedNews.news)
                },
                {
                    e -> Snackbar.make(news_list, e.message ?: "WZF", Snackbar.LENGTH_LONG).show()
                }
        )
        subscriptions.add(subscription)
    }


    private fun initAdapter() {
        if (news_list.adapter == null) {
            news_list.adapter = NewsAdapter()
        }
    }
}

Je suis assez nouveau sur RxJava - je serais vraiment heureux si quelqu'un pouvait m'aider avec ça. Merci.

7
myusername

Vous pouvez remplacer le gestionnaire d'erreurs Rx de la manière suivante:

  1. Étend la classe Application avec votre MyApplication personnalisée.
  2. Ensuite, écrivez ceci dans la méthode onCreate de votre classe d'application:

    @Override
    public void onCreate() {
        super.onCreate();
        RxJavaPlugins.setErrorHandler(throwable -> {}); // nothing or some logging
    }
    
  3. Ajoutez la classe MyApplication au manifeste:

    <application
        Android:name=".MyApplication"
        ...>
    

Pour plus d'informations, veuillez consulter Wiki RxJava

17
DenZap