RxJava 之 Android使用初體驗(yàn)

什么是RxJava##

  • RxJava 就是異步
  • RxJava 的異步實(shí)現(xiàn)睬罗,是通過(guò)一種擴(kuò)展的觀察者模式來(lái)實(shí)現(xiàn)的宿稀。
  • 一個(gè)響應(yīng)式編程框架

通過(guò)之前對(duì)RxJava的了解,我們已經(jīng)掌握了RxJava的一些基礎(chǔ)使用方法,下面我們結(jié)合一個(gè)簡(jiǎn)單的Demo,看看如何在Android 開發(fā)中使用RxJava阎毅。

RxAndroid 初體驗(yàn)###

需求####

這里我們的需求很簡(jiǎn)單:
點(diǎn)擊按鈕,執(zhí)行一個(gè)網(wǎng)絡(luò)請(qǐng)求点弯,將返回的json信息解析扇调,實(shí)現(xiàn)UI 更新

這也是我們做APP最常用的套路。首先看一下抢肛,我們需要 實(shí)現(xiàn)的效果狼钮。

RxAndroid

看到網(wǎng)上關(guān)于RxJava的網(wǎng)絡(luò)請(qǐng)求的內(nèi)容,都會(huì)提及Retrofit的使用捡絮,然而由于Retrofit使用了注解相關(guān)的內(nèi)容熬芜,代碼看起來(lái)會(huì)有點(diǎn)不好理解,這里我們就從最基礎(chǔ)的網(wǎng)絡(luò)請(qǐng)求出發(fā)福稳,一步一步理解一下RxAndroid的使用涎拉。

RxAndroid+OkHttp+Gson 實(shí)現(xiàn)數(shù)據(jù)更新####

OkHttp

OKHttp 大家應(yīng)該都了解,OkHttp 是基于http協(xié)議封裝的一套請(qǐng)求客戶端的圆。具體的細(xì)節(jié)就不展開說(shuō)了鼓拧,這里直接使用。

  • 我們創(chuàng)建OKHttpClient 和 Request
client = new OkHttpClient();
request = new Request.Builder()
                .url(BaseUrl)
                .build();
  • 創(chuàng)建Observeable (OKHttp 同步執(zhí)行)
private Observable<Response> HttpService() {
        Observable myObserve;

        myObserve = Observable.create(new Observable.OnSubscribe<Response>() {
            @Override
            public void call(Subscriber<? super Response> subscriber) {
                Response response = null;
                try {
                    response = client.newCall(request).execute();
                    subscriber.onNext(response);
                    subscriber.onCompleted();

                } catch (IOException e) {
                    subscriber.onError(e);
                }
            }

        });

這里我們通過(guò)oncreate 操作符創(chuàng)建了一個(gè)Observeable越妈,在其call 方法中執(zhí)行了OkHttp的一個(gè)同步get請(qǐng)求季俩,
網(wǎng)絡(luò)請(qǐng)求正常時(shí),將請(qǐng)求響應(yīng)Resoponse通過(guò)onNext方法返回梅掠,同時(shí)執(zhí)行onCompleted方法酌住。
網(wǎng)絡(luò)請(qǐng)求異常時(shí),將異常信息通過(guò)onError方法返回阎抒。

  • 訂閱者執(zhí)行subscribe
private void getData() {
        HttpService()
                .subscribe(new Subscriber<Response>() {
                    @Override
                    public void onCompleted() {
                        Log.e("onCompleted", "onCompleted");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("onError", e.getMessage());
                    }

                    @Override
                    public void onNext(Response response) {
                        if (response.isSuccessful()) {
                            try {
                                String json = response.body().string();
                                Log.e("onNext", json);
                                setView(json);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                });
    }

通過(guò)之前的學(xué)習(xí)酪我,我們知道在訂閱者(Subscribe)實(shí)現(xiàn)訂閱(subscribe)操作的同時(shí),Observeable就會(huì)開始發(fā)送事件挠蛉,在我們當(dāng)前的例子里祭示,就是開始執(zhí)行oncall方法肄满,通過(guò)OKHttp的網(wǎng)絡(luò)請(qǐng)求谴古,將請(qǐng)求到的信息Response通過(guò)onNext返回,而在訂閱者的onNext 方法里稠歉,我們處理Response信息掰担,實(shí)現(xiàn)UI更新也糊。

  • 指定正確的執(zhí)行線程

你應(yīng)該已經(jīng)注意到仅政,上面一個(gè)簡(jiǎn)單的流程里辩昆,我們進(jìn)行了網(wǎng)絡(luò)請(qǐng)求煎饼、UI更新等操作舀奶,而這些操作必然是在不同的線程中完成,這就要求我們整個(gè)操作流程必須實(shí)現(xiàn)正確的線程切換碌宴,RxJava 固然強(qiáng)大页慷,但也無(wú)法實(shí)現(xiàn)線程的智能切換 ,必須由我們?nèi)ブ付ê线m的線程执庐。所以我們上面的代碼是有問(wèn)題的酪耕,需要進(jìn)行如下修改:

private void getData() {
        HttpService()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Response>() {
                   onCompleted();
                    ......unchange
   }

這里我們的修改很簡(jiǎn)單,兩行關(guān)鍵代碼:

 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())

這兩行代碼指定了轨淌,我們的網(wǎng)絡(luò)請(qǐng)求在io線程執(zhí)行迂烁,不會(huì)阻塞主線程;UI更新確保在主線程中執(zhí)行递鹉。

總結(jié)來(lái)說(shuō)盟步,這里我們使用到了RxJava中的調(diào)度器,就是subscribeOn 指定了Observeable 執(zhí)行的線程躏结;而observeOn指定了Subscribe(訂閱者)執(zhí)行的線程却盘。

這樣我們非常簡(jiǎn)單實(shí)現(xiàn)了對(duì)線程的控制。

  • 以正確的方式更新UI

好了窜觉,我們現(xiàn)在可以放心的執(zhí)行g(shù)etData方法了 谷炸,在其onNext 方法,我們接收Response中的數(shù)據(jù):

這里分享一下禀挫,我在使用這個(gè)OKHttp 的Response時(shí)遇到一個(gè)坑:

Log.e("onNext", response.body().string());
String json = response.body().string();
Log.e("onNext", json);

執(zhí)行上面的三行代碼旬陡,你會(huì)發(fā)現(xiàn),第一次打印的日志是有數(shù)據(jù)的语婴,而第二次打印的日志數(shù)據(jù)卻是null描孟,第一次看到這個(gè)情況的時(shí)候,真的是讓我驚呆了砰左,后來(lái)看了body 方法的API才明白:

/**
   * Never {@code null}, must be closed after consumption, can be consumed only once.
   */
  public ResponseBody body() {
    return body;
  }

原來(lái)這個(gè)boby方法只能被執(zhí)行一次匿醒。這個(gè)真是有點(diǎn)坑啊2肌A帷!僻造!每次獲取數(shù)據(jù)都有打印日志的習(xí)慣憋他,真不知道只能執(zhí)行一次的意義是什么。

好了髓削,我們繼續(xù)竹挡,數(shù)據(jù)已經(jīng)能正確接收了,接下來(lái)就是解析數(shù)據(jù)并更新UI 了立膛。

public void setView(String json) {
        Gson gson = new Gson();
        DoubanBean douban = new DoubanBean();
        douban = gson.fromJson(json, DoubanBean.class);
        //
        Glide.with(mContext).load(douban.getIcon()).into(pic);
        title.setText(douban.getTitle());
        id.setText(douban.getId());

    }

這里我們用Gson 解析返回的json 格式數(shù)據(jù)揪罕,實(shí)現(xiàn)View 內(nèi)容更新梯码。

這里我們調(diào)用getData方法,結(jié)果發(fā)現(xiàn)頁(yè)面沒(méi)有任何變化好啰,看Logcat日志輸出:

E/onError: Permission denied (missing INTERNET permission?)

原來(lái)是我們忘記在AndroidManifest 文件中聲明網(wǎng)絡(luò)請(qǐng)求的權(quán)限了轩娶,這里執(zhí)行了onError 方法,返回了異常信息框往。

我們加上INTERNET 相關(guān)的權(quán)限之后罢坝,運(yùn)行程序,發(fā)現(xiàn)可以正常執(zhí)行了搅窿。

這里可以看到嘁酿,RxJava的響應(yīng)式編程思想中,對(duì)錯(cuò)誤的處理也是很理性的男应。

  • 創(chuàng)建Observeable (OKHttp 異步執(zhí)行)

之前我們創(chuàng)建Observeable的方式是通過(guò)OKHttp的同步get請(qǐng)求方式闹司,如果用異步請(qǐng)求方式怎么做呢?

     // OkHttp 異步執(zhí)行
        myObserve=Observable.create(new Observable.OnSubscribe<Response>() {
            @Override
            public void call(final Subscriber<? super Response> subscriber) {
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        subscriber.onError(e);
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        subscriber.onNext(response);
                        subscriber.onCompleted();
                    }
                });
            }
        });

看以看到沐飘,和同步請(qǐng)求方式不同的是游桩,我們將onNext ,onCompleted 和 onError這些回調(diào)方法放在了OKHttp自己的回調(diào)里進(jìn)行執(zhí)行。這樣做的唯一優(yōu)點(diǎn)可能就是我們?cè)趫?zhí)行訂閱的時(shí)候不用指定Observeable(網(wǎng)絡(luò)請(qǐng)求)執(zhí)行的線程了耐朴,因?yàn)樗旧砭褪钱惒降慕栉裕褪沁@里:

private void getData() {
        HttpService()
                //okHttp 異步執(zhí)行時(shí),無(wú)需指定網(wǎng)絡(luò)請(qǐng)求的線程
//                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .......
    }

當(dāng)然筛峭,OkHttp終究只是對(duì)網(wǎng)絡(luò)請(qǐng)求做了一次封裝的庫(kù)铐刘,和最基礎(chǔ)的HttpClient, HttpUrlConnection的功能是一樣的,不像Volley影晓、android-async-http這些庫(kù)镰吵;無(wú)論同步執(zhí)行還是異步執(zhí)行,其請(qǐng)求結(jié)果始終是在子線程挂签,所以我們的Subscribe對(duì)于UI的更新還是需要指定其為mainThread 的疤祭。

這里可以看出,使用異步的OKHttp反而有點(diǎn)多余了饵婆。

后話###

這里我們通過(guò) RxAndroid+OkHttp+Gson 的方式勺馆,以一種最費(fèi)勁的方式實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的需求(這個(gè)Demo真的很爛),只是為了闡述RxJava 的編程思想在Android中使用的體驗(yàn)侨核。這里的需求草穆,通過(guò)AsnycTask 或者OkHttp + Handler 的方式實(shí)現(xiàn)是非常簡(jiǎn)單的,就不再詳述了芹关。

RxJava 的作用就是實(shí)現(xiàn)異步续挟,如果我們?cè)镜牟僮鞅緛?lái)就是異步紧卒,為了使用RxJava而硬套進(jìn)去是不合理的侥衬,反而顯得有點(diǎn)不倫不類,這里我們從Observeable的創(chuàng)建使用OkHttp 的同步&異步請(qǐng)求就可以看出,使用異步請(qǐng)求并沒(méi)有多大益處轴总,反而丟掉了RxJava可以指定線程的優(yōu)點(diǎn)直颅。

RxJava的使用并不能使我們的程序運(yùn)行更高效,或者可以實(shí)現(xiàn)了別的框架實(shí)現(xiàn)不了的功能怀樟。只是對(duì)我們編寫代碼的方式提供了一種更好的思路功偿。


好了,RxJava 基礎(chǔ)到這里就結(jié)束了往堡。文中所講的Demo在GitHub中也有械荷,感興趣的同學(xué)可以點(diǎn)這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末虑灰,一起剝皮案震驚了整個(gè)濱河市吨瞎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌穆咐,老刑警劉巖颤诀,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異对湃,居然都是意外死亡崖叫,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門拍柒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)心傀,“玉大人,你說(shuō)我怎么就攤上這事拆讯【绨” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵往果,是天一觀的道長(zhǎng)疆液。 經(jīng)常有香客問(wèn)我,道長(zhǎng)陕贮,這世上最難降的妖魔是什么堕油? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮肮之,結(jié)果婚禮上掉缺,老公的妹妹穿的比我還像新娘。我一直安慰自己戈擒,他們只是感情好眶明,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著筐高,像睡著了一般搜囱。 火紅的嫁衣襯著肌膚如雪丑瞧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天蜀肘,我揣著相機(jī)與錄音绊汹,去河邊找鬼。 笑死扮宠,一個(gè)胖子當(dāng)著我的面吹牛西乖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坛增,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼获雕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了收捣?” 一聲冷哼從身側(cè)響起典鸡,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坏晦,沒(méi)想到半個(gè)月后萝玷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昆婿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年球碉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仓蛆。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡睁冬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出看疙,到底是詐尸還是另有隱情豆拨,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布能庆,位于F島的核電站施禾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏搁胆。R本人自食惡果不足惜弥搞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渠旁。 院中可真熱鬧攀例,春花似錦、人聲如沸顾腊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)杂靶。三九已至梆惯,卻和暖如春酱鸭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背加袋。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抱既,地道東北人职烧。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像防泵,于是被迫代替她去往敵國(guó)和親蚀之。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容