Retrofit2+Rxjava-Rxjava2.x-篇一-用起來

從Retrofit基本用法MonkeyLei:Retrofit+Rxjava-以自己的方式重頭開始-入門篇 -> 到Convert MonkeyLei:Retrofit+Rxjava-ConverterFactory-篇一-先了解一下 -> 到CallAdapter MonkeyLei:Retrofit+Rxjava-CallAdapterFactory-篇一-先簡單自定義看看 -> 到今天的RxJava ReactiveX/RxJava(看了一眼,東西還蠻多。頭一回正兒八經的看,有些見都沒見過。只怪平時搬磚太多了~~~~) - 這篇官方也看,磚也搬,主要是官方東西太多了,段時間搞不定!想快速搞搞...

RxJava Javadoc 2.2.9 - 小萌新會先了解下基本的介紹呀,用法呀。然后重點是Retrofit+RxJava的結合用法,然后基本上串聯起來!之后補一些遺漏的基本知識,再之后就是深入和封裝。

開始前,我們復習一下Retrofit的基本用法流程,以及過程中部分的Okttp的知識。

直接上代碼:都是之前的案例,新建了一個頁面來實踐 FanChael/RxNet

Repo.kt

package com.hl.rxnettest

class Repo{
    var id: Long = -1
    public var name: String? = null
    var full_name: String? = null
    // class owner - not need
    var html_url: String? = null
    var description: String? = null
} 

GitHubService.kt

package com.hl.rxnettest

import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Path

interface GitHubService {
    // 添加GsonConverterFactory解析器 - 返回Json解析的對象列表
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String): Call<List<Repo>>
}

Main2Activity.kt

package com.hl.rxnettest

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException

class Main2Activity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 布局都不依賴了
        // setContentView(R.layout.activity_main2)
        // setContentView(View(this))

        // 1\. 創建Retroft實例對象
        var retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://api.github.com/")
                .build();

        // 2\. 創建GitHub請求服務
        var gitHubService = retrofit.create(GitHubService::class.java);

        // 3\. 獲取服務對應的某個請求實例
        var gitCall  = gitHubService.listRepos("FanChael");

        // 4.1 UI線程不能進行同步請求,ANR
        // var executeRst = gitCall.execute();
        // 4.2\. 進行異步請求
        gitCall.enqueue(object : Callback<List<Repo>>{  // object的作用是調用內部匿名類
            override fun onResponse(call: Call<List<Repo>>?, response: Response<List<Repo>>?) {
                // {protocol=http/1.1, code=200, message=OK, url=https://api.github.com/users/FanChael/repos}
                Log.e("Main2Activity", "" + response)
                Log.e("Main2Activity", "" + (response?.body() ?: ""))
                var repoList = response?.body();
                for (item in repoList!!) {
                    // SuperStartElectronic subtitle display - 電子字幕展示-接機、演唱會、見面、展示專用.https://github.com/FanChael/SuperStart
                    Log.e("Main2Activity", item.name + item.description + item.html_url)
                }
            }
            override fun onFailure(call: Call<List<Repo>>?, t: Throwable?) {
            }
        })
        // 4.3 獲取okhttp3.Request原始請求對象實例 - 用原始請求對象進行請求
        var request = gitCall.request()
        // --然后創建一個Call對象,用于網絡請求
        var okHttpCall = OkHttpClient().newCall(request)
        // ---然后進行異步請求
        okHttpCall.enqueue(object: okhttp3.Callback{
            override fun onFailure(call: okhttp3.Call?, e: IOException?) {
            }

            override fun onResponse(call: okhttp3.Call?, response: okhttp3.Response?) {
                // [{"id":140240588,"node_id":"MDEwOlJlcG9zaXRvcnkxNDAyNDA1ODg=",....]
                Log.e("Main2Activity", "okhttp3: " + (response?.body()?.string() ?: ""))
            }

        }) // 我們采用Okhttp的方式進行請求調用,與Retrofit如出一轍,Retrofit進行了包裝,簡化了請求定義!

    }
}

其中Retrofit也返回了原始的Okhttp請求實例,那樣某些用戶就可以進行個性化定制,想到還是周到嘛。雖然我們不用,但是其他人可能需要妮!

image

OkHttp的知識可以了解下,好早以前,小萌新也有用過,當時主流的是XUtils請求框架,不過該框架已經停止維護了!都是大佬,點個贊!https://square.github.io/okhttp/

image

如果要想自己,就看官網的案例,簡單過過,然后看API就可以花時間研究了.... 再懶點就看網友的分析: OKhttp3 的同步和異步請求基本用法

另外小萌新之前記錄了一個關于https認證的問題 MonkeyLei:Android-Okhttp3之https證書未認證的問題(轉載完善,修復過時方法)

Now,Let's Start....

  1. 添加依賴呀...最新2.2.9
image

2. Hello World走起, 此時Flowable不知道是啥,不過案例可以跑起來,一調用just,哇,好多參數提示喲...厲害..

image
        // lambdas的搞法..Flowable為何物?
        Flowable.just("hello world", "hello world2", "hello world3")
                .subscribe(System.out::println)
        // 不支持java8的lambdas的用法
        Flowable.just("hello world all")
                .subscribe(object: Consumer<String> {
                    override fun accept(t: String) {
                        System.out.println(t);
                    }
                })
image

3. 此時看看RxJava都提供了哪些類了

Base classes
RxJava 2 features several base classes you can discover operators on:

io.reactivex.Flowable: 0..N flows, supporting Reactive Streams and backpressure
io.reactivex.Observable: 0..N flows, no backpressure,
io.reactivex.Single: a flow of exactly 1 item or an error,
io.reactivex.Completable: a flow without items but only a completion or error signal,
io.reactivex.Maybe: a flow with no items, exactly one item or an error.

小萌新會先了解下Flowable、然后Single、Completable、Maybe簡單看看先。完事了重點看下Observable,因為之前項目都是它.

3.1 [Flowable](https://link.zhihu.com/?target=http%3A//reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html) - 0..N flows, supporting Reactive-Streams and backpressure

Reactive-Streams operates with Publishers which Flowable extends. Many operators therefore accept general Publishers directly and allow direct interoperation with other Reactive-Streams implementations.

The Flowable hosts the default buffer size of 128 elements for operators, accessible via [bufferSize()](https://link.zhihu.com/?target=http%3A//reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html%23bufferSize--), that can be overridden globally via the system parameter rx2.buffer-size. Most operators, however, have overloads that allow setting their internal buffer size explicitly.

The documentation for this class makes use of marble diagrams. The following legend explains these diagrams:

image

For more information see the ReactiveX documentation.

一臉懵逼:大概說什么響應式,緩存buffer-size啥的 - 支持響應式和背壓 (Look it. https://blog.csdn.net/weixin_33691598/article/details/86861027 )??淳W友的分析吧。。先了解各大概吧..

image

Rxjava2入門教程五:Flowable背壓支持——對Flowable最全面而詳細的講解

人家順便把其他幾個簡化版的單一處理的方式的Observable也說了。厲害了。。我忒么一點不懂呀!希望后面自己有所感悟...鏈接先放這里。自己回頭感悟感悟再來膜拜一下可好...

Rxjava2入門教程六:Single、Completable、Maybe——簡化版的Observable

https://blog.csdn.net/fengluoye2012/article/details/79297186

3.2 [Observable](https://link.zhihu.com/?target=http%3A//reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable.html) - 0..N flows, no backpressure

**[Flowable](https://link.zhihu.com/?target=http%3A//reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable.html)**比較完善,是RxJava2.0相對1.0的改進,支持了多個響應,同時支持背壓處理,保證發射的很多數據不會因為積壓問題導致內存溢出等問題,但是同時也帶來了性能和處理速度的問題,這種一般適合相對大的項目大的處理請求的情況。而Observable則不支持背壓處理,像我們Android的話,每個頁面數據相對都是比較單一,不會很大的數據發射以及處理,所以一般看到的都是Observable的方式。Flowable就相對陌生多了....

當一段時間內項目相對較少(<1000)時使用Observable和/或沒有生產者過度消費消費者的風險,從而導致OOM. 當您擁有相對大量的項目時使用Flowable,您需要仔細控制Producer的行為方式,以避免資源耗盡和/或擁塞. 背壓
如果你有一個可觀察到的物品如此快速地發射物品,消費者無法跟上流量,導致已發射但未消耗的物品存在.

背壓策略處理的是由觀察者發出但未被訂戶消費的未消耗物品如何被管理和控制. 

ReactiveX/RxJava 上面也有如似說明

In RxJava, the dedicated Flowable class is designated to support backpressure and Observable is dedicated for the non-backpressured 
operations (short sequences, GUI interactions, etc.). The other types, Single, Maybe and Completable don't support backpressure nor should they;
 there is always room to store one item temporarily.

3.1/3.2 跟著一起練習下怎么用吧,官方的看著好難呀,去搬磚一下別人寫的好的吧... https://mp.weixin.qq.com/s?__biz=MzIwMzYwMTk1NA%3D%3D&mid=2247484711&idx=1&sn=c3837b7cad21f0a69d7dccd1aaaf7721&chksm=96cda46aa1ba2d7ce145472449e5a832cd3ac0bc1f766fe09f1ce68ca46c16bab645e507f0b5

然后來個練習熟悉下Flowable(說的不當的注釋后面補救):

       // 上游Flowable
        var upstream = Flowable.create(object: FlowableOnSubscribe<Integer> {
            override fun subscribe(emitter: FlowableEmitter<Integer>) {
                for (index in 1..10000){
                    emitter.onNext(Integer(index))
                }
                emitter.onComplete()
            }
        }, BackpressureStrategy.BUFFER)
        // 為上游指定一個線程 - 又比如 -> .subscribeOn(Schedulers.io())
        upstream.subscribeOn(Schedulers.newThread()) // Now, 不懂
        // 為下游指定一個線程 - 比如Android指定AndroidUI線程 -> .observeOn(AndroidSchedulers.mainThread())
        upstream .observeOn(Schedulers.newThread())
        upstream.subscribe(object: Subscriber<Integer>{
            override fun onComplete() {
                Log.e("rxjava", "onComplete");
                Toast.makeText(this@Main2Activity, "OK", Toast.LENGTH_SHORT).show()
            }

            override fun onSubscribe(s: Subscription?) {
                // 發起請求尼 - 跳過去看源碼不懂,反正就是:只有調用了這個方法上游才會發送事件
                // n the strictly positive number of elements to requests to the upstream - 需要一個嚴格的正數去請求上游發送數據?
                s?.request(java.lang.Long.MAX_VALUE)
            }

            override fun onNext(t: Integer?) {
                // 一秒鐘處理一條
                Thread.sleep(1000)
                Log.e("rxjava", "upstream's value=" + t);
            }

            override fun onError(t: Throwable?) {
            }

        })

其中作者關于request有解釋,小萌新看了下,不錯,還是比較好理解一點的:

  這是因為Flowable在設計的時候采用了一種新的思路也就是響應式拉取的方式來更好的解決上下游流速不均衡的問題, 與我們之前所講的控制數量和控制速度不太一樣, 
這種方式用通俗易懂的話來說就好比是葉問打鬼子, 我們把上游看成小日本, 把下游當作葉問, 當調用Subscription.request(1)時, 葉問就說我要打一個! 
然后小日本就拿出一個鬼子給葉問, 讓他打, 等葉問打死這個鬼子之后, 再次調用request(10),  葉問就又說我要打十個! 然后小日本又派出十個鬼子給葉問, 
然后就在邊上看熱鬧, 看葉問能不能打死十個鬼子, 等葉問打死十個鬼子后再繼續要鬼子接著打...
  所以我們把request當做是一種能力, 當成下游處理事件的能力, 下游能處理幾個就告訴上游我要幾個, 這樣只要上游根據下游的處理能力來決定發送多少事件, 
就不會造成一窩蜂的發出一堆事件來, 從而導致OOM. 這也就完美的解決之前我們所學到的兩種方式的缺陷, 過濾事件會導致事件丟失, 減速又可能導致性能損失. 
而這種方式既解決了事件丟失的問題, 又解決了速度的問題, 完美 !
   但是太完美的東西也就意味著陷阱也會很多, 你可能只是被它的外表所迷惑, 失去了理智, 如果你濫用或者不遵守規則, 一樣會吃到苦頭.
比如這里需要注意的是, 只有當上游正確的實現了如何根據下游的處理能力來發送事件的時候, 才能達到這種效果, 如果上游根本不管下游的處理能力, 
一股腦的瞎他媽發事件, 仍然會產生上下游流速不均衡的問題, 這就好比小日本管他葉問要打幾個, 老子直接拿出1萬個鬼子, 這尼瑪有種打死給我看看? 
那么如何正確的去實現上游呢, 這里先賣個關子, 之后我們再來講解.

東西還是多呀,我好菜,(。?_?。)?I’m sorry~ 有點看不懂了,今天累累的...

快速接觸下**[Observable](https://link.zhihu.com/?target=http%3A//reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable.html)**

一個官方的案例,先跑起來看一眼:

        /*
        由于在RxJava在2.x以上版本,api改動還是比較大的.
        其中訂閱時有兩個Api : subscribe和subscribeWith,很多人可能不太明白應該使用哪個
        我的理解就是subscribeWith中會把方法參數返回回去接收的是ResourceSubscriber,
        而ResourceSubscriber實現了Disposable接口所以,一般subscribeWith用到使用Rx請求接口的這種情況,訂閱后把請求參數返回回去,可以添加到CompositeDisposable中方便綁定Activity生命周期取消
        其實subscribe中除了重載參數是Observer的其他也都返回了Dispose對象,至于為什么這個方法沒有返回暫時也不知道作者怎么想的.
        因為它返回值是void所以在請求接口時最好還是使用subscribeWith,添加訂閱關系更方便了
         */
        // 別引錯包了,是io.reactivex,不是rx.Observable
        var d = Observable.just("Hello world!")
                .delay(1, TimeUnit.SECONDS)
                .subscribeWith(object : DisposableObserver < String >() {
                    override fun onStart() {
                        Log.e("rxjava", "Start");
                    }
                    override fun onNext(t: String) {
                        Log.e("rxjava", "" + t);
                    }
                    override fun onError(t: Throwable) {
                        t.printStackTrace();
                    }
                    override fun onComplete() {
                        Log.e("rxjava", "Done");
                    }
                });
         Thread.sleep(500);
        // the sequence can now be disposed via dispose() - 隔了一會里面取消,則收不到結果
        // d.dispose();
image

那我們接著看看別的寫法:

       // 1\. 創建一個被觀察者
        val observable = Observable.create(ObservableOnSubscribe<String> { emitter ->
            Log.d("observable", "observable")
            emitter.onNext("1")
            emitter.onNext("2")
            emitter.onNext("3")
            emitter.onComplete()
        })

        // 2\. 創建一個訂閱者(觀察者)
        val observer = object : Observer<String> {
            override fun onSubscribe(d: Disposable) {
                Log.e("observable", "onSubscribe")
            }

            override fun onNext(s: String) {
                Log.e("observable", s)
            }

            override fun onError(e: Throwable) {
                Log.e("observable", "onError")
            }

            override fun onComplete() {
                Log.e("observable", "onComplete")
            }
        }

        // 訂閱收消息(關聯觀察者與被觀察者)
        observable.subscribe(observer);

這個看著好像還行的樣子...這篇文章寫的和比喻的比較可以

image

RxJava2系列第一篇---基本使用 作為我們這些小白,還是適合看看的。。

目前來看,也只是知道簡單使用。。還不行。小萌新還想就是看子線程,UI線程那種方式怎么搞?所以Observer還需要實踐一下才行,就像這樣的解釋 RxJava2系列第二篇---異步

再來段解釋加深下印象:

image

**再接著-接著看看別的寫法: **Consumer也可以作為簡單的觀察者,接收上游數據(就是很多狀態回調都沒得了) - 有時候或許我們就只需要接收數據,什么錯誤,完成可能都不需要(比如推送信息來了,如果正常有數據就提示用戶,類似這樣的操作可能就不需要做任何錯誤完成處理...)

        // 簡單點也可以Consumer作為觀察者 - 很多狀態可能就沒有了
        observable.subscribe(object: Consumer<String>{
            override fun accept(t: String?) {
                // "a" "b" "c"
                Log.e("observable accept", t)
            }
        })

接著我們看看線程相關的,就是說我們目前的上游,下游是在哪個線程,為什么之前的實踐可以Toast,如下:

        // 1\. 默認是在當前的主線程(UI線程中) - 結果都是: thread'name=main
        val observable2 = Observable.create(ObservableOnSubscribe<String> { emitter ->
            Log.e("observable", "thread'name=" + Thread.currentThread().name)
            emitter.onNext("Hello I'm comming.")
            emitter.onComplete()
        })
        observable2.subscribe(object : Consumer<String> {
            override fun accept(t: String?) {
                // main線程中,可以進行ui操作
                Toast.makeText(this@Main2Activity, "OK", Toast.LENGTH_SHORT).show()
                Log.e("observable", "thread'name=" + Thread.currentThread().name)
            }
        })

        // 將處理放到一個子線程中去進行處理...我們可能要進行網絡請求
        Thread(Runnable {
            // 2\. 默認是在當前的子線程中 - 結果都是: thread'name=Thread-2
            val observable3 = Observable.create(ObservableOnSubscribe<String> { emitter ->
                Log.e("observable", "thread'name=" + Thread.currentThread().name)
                emitter.onNext("Hello I'm comming.")
                emitter.onComplete()
            })
            observable3.subscribe(object : Consumer<String> {
                override fun accept(t: String?) {
                    // 不能操作UI - 非main(UI)線程
                    // Toast.makeText(this@Main2Activity, "OK", Toast.LENGTH_SHORT).show()
                    Log.e("observable", "thread'name=" + Thread.currentThread().name)
                }
            })
        }).start()

我們分別在主線程(UI線程)和新開的線程中進行了當前線程信息的打印,如果默認沒有指定上下游線程的情況下,外面的都是在main線程中;里面的都是出于新的子線程中。從打印結果也可以看到:

image

如果要結合Android實際情況,上游做網絡請求處理,然后給到下游,下游可能涉及到提示,界面刷新等操作。很明顯程序就炸了!So,此前我們經常用的subscribeOn、observeOn就發揮了至關作用! 一開始和我一樣懵懵的我們,只是搬來用的我們,總算可以多理解一些了:

subscribeOn - 指定上游所在線程

observeOn - 指定下游所在線程

上線處于子線程,負責發送網絡請求,下游處于主線程,負責更新UI,RxJava線程調度器就干了這個事情。所以為什么,我們要引入Retrofit+RxJava,還得配合AndroidSchedulers來實現更優雅的網絡請求!實現小萌新的MVP架構尼...

改造如下:

        // 將處理放到一個子線程中去進行處理...我們可能要進行網絡請求
        Thread(Runnable {
            // 2\. 默認是在當前的子線程中 - 結果都是: thread'name=Thread-2
            val observable3 = Observable.create(ObservableOnSubscribe<String> { emitter ->
                Log.e("observable", "thread'name=" + Thread.currentThread().name)
                emitter.onNext("Hello I'm comming.")
                emitter.onComplete()
            })
            observable3.subscribe(object : Consumer<String> {
                override fun accept(t: String?) {
                    // 不能操作UI - 非main(UI)線程
                    // Toast.makeText(this@Main2Activity, "OK", Toast.LENGTH_SHORT).show()
                    Log.e("observable", "thread'name=" + Thread.currentThread().name)
                }
            })

            // 3\. 默認是在當前的子線程中 - 結果都是: thread'name=Thread-2
            val observable4 = Observable.create(ObservableOnSubscribe<String> { emitter ->
                Log.e("observable", "thread'name=" + Thread.currentThread().name)
                emitter.onNext("Hello I'm comming.")
                emitter.onComplete()
            })
            observable4.subscribeOn(Schedulers.newThread()) // 指定上游是一個新的線程
                    .observeOn(AndroidSchedulers.mainThread())  // 指定下游是一個Android 主線程/UI線程
                    .subscribe(object : Consumer<String> {
                        override fun accept(t: String?) {
                            // 切換到main(UI)線程
                            Toast.makeText(this@Main2Activity, "OJBK", Toast.LENGTH_SHORT).show()
                            Log.e("observable", "thread'name=" + Thread.currentThread().name)
                        }
                    })
        }).start()

RxJava線程調度器可以呀!

image

注意1,有時候我們用的是http://Schedulers.io()來指定上游線程?如下

image

解釋 from 網友:

您應該考慮使用線程池的主要原因是它們保留了一些空閑并等待工作的預創建線??程。
這意味著當你有工作要做時,你不需要花費創建線程的開銷。一旦你的工作完成,該線程也可以重新用于未來的工作,而不是不斷創建和銷毀線程。

創建線程可能會很昂貴,因此最大限度地減少正在創建的線程數量通常很好。

有關線程池的更多信息,我建議:

Java中的線程池有什么用?
什么是線程池?
線程池模式(Wikipedia)

注意2 多次指定上下游所在線程的情況 - 給老哥打個廣告

image

另外還需要關注一下RxJava1.x和RxJava2.x的一些區別,比如Observable的不同,創建方式的區別,小萌新之前用的是1.x的版本,現在發現如果導入以前的包,官方的一些案例里面的一些方法都沒法調用!這個需要關注下,核心的邏輯思想一致,不過用法需要特別注意!

**注意4: **Rxjava 1.x 版本、Rxjava 2.x版本關于CallAdapterFactory的區別,由于舊版本的RxJavaCallAdapterFactory不支持RxJava2.x,但是jakewharton大神怎么能不解決了,隨后就有了新版的rxjava2版本的適配器 square/retrofit 完善下如下依賴!

image

繼續在Rxjava2.x上用舊版本適配器適配器問題:addCallAdapterFactory(RxJavaCallAdapterFactory.create()),報錯如下: Unable to create call adapter for io.reactivex.Observable

  06-19 10:53:38.840 11284-11291/? E/zygote64: Failed sending reply to debugger: Broken pipe
06-19 10:54:04.780 11284-11363/com.hl.rxnettest E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: com.hl.rxnettest, PID: 11284
    java.lang.IllegalArgumentException: Unable to create call adapter for io.reactivex.Observable<java.util.List<com.hl.rxnettest.Repo>>
        for method GitHubService.listReposStringRxJavaObservable
        at retrofit2.Utils.methodError(Utils.java:52)
        at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:105)
        at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:66)
        at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:37)
        at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:170)
        at retrofit2.Retrofit$1.invoke(Retrofit.java:149)
        at java.lang.reflect.Proxy.invoke(Proxy.java:913)
        at $Proxy0.listReposStringRxJavaObservable(Unknown Source)
        at com.hl.rxnettest.Main2Activity$onCreate$1.run(Main2Activity.kt:271)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for io.reactivex.Observable<java.util.List<com.hl.rxnettest.Repo>>.
      Tried:
       * retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
       * retrofit2.CompletableFutureCallAdapterFactory
       * retrofit2.DefaultCallAdapterFactory
        at retrofit2.Retrofit.nextCallAdapter(Retrofit.java:241)
        at retrofit2.Retrofit.callAdapter(Retrofit.java:205)
        at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:103)
            ... 8 more

RxJava2出現:Unable to create call adapter for io.reactivex.Flowable 網友也有說明尼!

HL. 我們就可以來個github倉庫的請求看看,走起...

        // 來個網絡請求案例壓壓驚
        // 1\. 創建Retroft實例對象
        var retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                // 別忘記了加支持RxJava2的適配器:舊版的別了呀 https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl("https://api.github.com/")
                .build();

        // 2\. 創建GitHub請求服務
        var gitHubService = retrofit.create(GitHubService::class.java);

        // 3\. 獲取服務對應的某個請求實例
        var gitCall = gitHubService.listReposStringRxJavaObservable("FanChael");

        // 4\. RxJava請求走起
        var ds: Disposable ? = null
        gitCall.subscribeOn(Schedulers.io()) // 指定上游一個子線程
                .observeOn(AndroidSchedulers.mainThread())  // 指定下游UI/主main線程
                .subscribe(object : Observer<List<Repo>> {
                    override fun onComplete() {
                    }

                    override fun onSubscribe(d: Disposable) {
                        // 保存起來,后面可以做一些取消處理
                        ds = d;
                    }

                    override fun onNext(t: List<Repo>) {
                        Toast.makeText(this@Main2Activity, "OJBK", Toast.LENGTH_SHORT).show()
                        Log.e("observable", "thread'name=" + Thread.currentThread().name)
                        for (item in t) {
                            // SuperStartElectronic subtitle display - 電子字幕展示-接機、演唱會、見面、展示專用.https://github.com/FanChael/SuperStart
                            Log.e("observable", item.name + item.description + item.html_url)
                        }
                    }

                    override fun onError(e: Throwable) {
                    }
                })
        // 可以做取消請求處理
        //        if (null != ds && !ds!!.isDisposed) {
        //            ds!!.dispose()
        //        }

一看,OK啦...

  用過了RxJava1.x,再來用用RxJava2.x,還是有好處的哈! 有些問題能追溯一下...
image

對了,還有個.map的數據中間處理的過程(之前rxjava1.x的時候用的),小萌新還沒添加,添加下:

image

所以,改造下,**增加一個map - 操作符的相關 **https://blog.csdn.net/oneblue123/article/details/79784620 - 有必要了解一下,改天可以針對你的項目做優化和完善滴!

         // 來個網絡請求案例壓壓驚
        // 1\. 創建Retroft實例對象
        var retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                // 別忘記了加支持RxJava2的適配器:舊版的別了呀 https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl("https://api.github.com/")
                .build();

        // 2\. 創建GitHub請求服務
        var gitHubService = retrofit.create(GitHubService::class.java);

        // 3\. 獲取服務對應的某個請求實例
        var gitCall = gitHubService.listReposStringRxJavaObservable("FanChael");

        // 4\. RxJava請求走起
        var ds: Disposable ? = null
        gitCall.subscribeOn(Schedulers.io()) // 指定上游一個子線程
                .observeOn(AndroidSchedulers.mainThread()) // 指定下游UI/主main線程
                // 創建一個動態鍵的 observable 映射。 如果你不但想對一個特定項的更改做出反應,而且對添加或刪除該項也做出反應的話,那么 observable 映射會非常有用
                .map { t ->  // lambda表達式樣式呀
                    Log.e("observable", "map thread'name=" + Thread.currentThread().name)
                    var userList: MutableList<Repo> = ArrayList()
                    for (item in t){
                        if (item.name?.contains("banner")!!){
                            userList.add(item)
                        }
                    }
                    userList
                }
                .subscribe(object : Observer<List<Repo>> {
                    override fun onComplete() {
                    }

                    override fun onSubscribe(d: Disposable) {
                        // 保存起來,后面可以做一些取消處理
                        ds = d;
                    }

                    override fun onNext(t: List<Repo>) {
                        Toast.makeText(this@Main2Activity, "OJBK", Toast.LENGTH_SHORT).show()
                        Log.e("observable", "thread'name=" + Thread.currentThread().name)
                        for (item in t) {
                            // SuperStartElectronic subtitle display - 電子字幕展示-接機、演唱會、見面、展示專用.https://github.com/FanChael/SuperStart
                            Log.e("observable", item.name + item.description + item.html_url)
                        }
                    }

                    override fun onError(e: Throwable) {
                    }
                })
        // 可以做取消請求處理
        //        if (null != ds && !ds!!.isDisposed) {
        //            ds!!.dispose()
        //        }
image

附上: 這有個網友的升級筆記,很nice RxJava1.X升級到RxJava2.X筆記

小萌新之前的RxJava1.x方式(沒有做封裝的一個項目的寫法,封裝后利用泛型做了通用處理,所以AuthorBean這些都是泛型T替代了的。。。)如下:

image

這篇基礎認識先這樣吧,搞了兩天了。。官方看,別人的分析看,自己實踐試試看,都一起整整了看了下。。算是更熟悉一步了。。下一篇的話,打算把RxJava2.x + Retrofit2.x的網絡請求中異常處理,數據請求預處理,請求信息預包裝等來搞搞。為進一步認知以及后續的封裝做準備!

補上一篇感覺還不錯的方法的全面說明: RxJava2 只看這一篇文章就夠了 - 每個說明都有案例,幫助你理解入門

FanChael/RxNet 倉庫地址

補補提醒:onNext經過指定AndroidSchedulers.mainThread()后,切換到了UI線程,但是如果你Thread.sleep(10000)發現并不會ANR,But,如下:

   ANR是指系統沒有響應,但是耗時操作不一定會造成ANR
   但ANR通常是因為在UI線程中做了耗時操作引起的
   就是說耗時操作有可能會造成ANR,也有可能不回

如果你進行網絡同步請求,指定會炸的:

                       // UI線程規定不能進行耗時的操作,但是不一定耗時都會引起ANR;只要不影響UI渲染的卡頓,不一定會引起ANR
                        Thread.sleep(100000)
                        /* UI線程中不能進行 okhttp同步請求
                        val client = OkHttpClient.Builder()
                                .build();
                        val request = Request.Builder().url("http://www.baidu.com").get().build()
                        val requestCall = client.newCall(request)
                        val response = requestCall.execute()
                        if (response.isSuccessful()) {
                            val json = response.body()?.string();
                            Log.e("observable", "json=" + json)
                        } */

操作符除了map,還有flatmap這些,能解決for循環處理數據嵌套的問題,幫你簡化預處理數據的操作流程,熟悉了應該事半功倍!

https://blog.csdn.net/baidu_31093133/article/details/78744911

如果你想針對Retrofit請求數據進行預處理,然后給到onNext,你可以再包裝一層Observable進行耗時處理,然后給到onNext的UI線程進行渲染...暫時先入門記錄到這吧。只能說又熟悉了一天了。。。和網友請教學習了一番...思路清晰多了!目前來看是有了相對清晰的脈絡了...加油,我是菜鳥,我很丑但是很溫柔!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容