RxJava2修煉之路(二)

RaJava2修煉之路——易容術(shù)

上一篇講解了RxJava的原理之后唁奢,本篇繼續(xù)深入了解一下RxJava對(duì)執(zhí)行任務(wù)的線程調(diào)度抱慌。

目的

在每個(gè)剛學(xué)Android的小白來講推沸,必須牢記的的一點(diǎn)就是子線程不能跟新UI,所有跟新UI的操作必須放在主線程(也就是UI線程)蔚携,問什么呢房维?因?yàn)闀?huì)造成界面卡頓或者ANR啊傻粘,如果你想問什么是ANR懊拷选?那你就先去查一下資料充點(diǎn)電再來看本篇文章弦悉,如果任何跟新UI的操作在子線程中程序就會(huì)奔潰窒典。下面是我寫的一個(gè)案例,利用Handler來跟新UI:

 handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d(TAG, "handleMessage: "+Thread.currentThread().getName());
                if(msg.what == 0x01){
                    Bitmap bmp = (Bitmap) msg.obj;
                    loadPic(bmp);
                }
            }
        };

  /**
     * 跟新UI
     *
     * @param bmp
     */
    private void loadPic(Bitmap bmp) {
        img.setImageBitmap(bmp);
    }
    @Override
    protected void onResume() {
        super.onResume();
        new Thread() {//開啟圖片下載線程
            @Override
            public void run() {
                Bitmap bmp = loadImage();
                Message msg = handler.obtainMessage();
                msg.obj = bmp;
                msg.what = 0x01;
                handler.sendMessage(msg);
            }
        }.start();
    }

    /**
     * 圖片下載
     *
     * @return
     */
    private Bitmap loadImage() {
        Bitmap bmp = null;
        try {
            URL url = new URL(mUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(8 * 1000);
            conn.setReadTimeout(8 * 1000);
            InputStream is = conn.getInputStream();
            bmp = BitmapFactory.decodeStream(is);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bmp;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);// 移除所有handler的消息回調(diào)
    }

是一個(gè)很簡(jiǎn)單的網(wǎng)絡(luò)加載圖片,然后顯示在UI界面稽莉,在OnResume中開啟線程執(zhí)行加載圖片的耗時(shí)操作瀑志,圖片加載完成后將圖片填充到message中傳遞到HandlerMessage中,執(zhí)行UI跟新,Handler是Android中一塊很重要的知識(shí)點(diǎn)劈猪,不太清楚的小伙伴去查資料補(bǔ)一下吧昧甘。

實(shí)現(xiàn)

我們首先看你一下RxJava中事件發(fā)送和接受分別在那個(gè)線程:

     Observable.create(new ObservableOnSubscribe<String >() {
            @Override
            public void subscribe(ObservableEmitter<String > e) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
                 e.onNext("hello world");
                 e.onComplete();
            }
          }).subscribe(new Consumer<String >() {
            @Override
            public void accept(String  str) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
            }
        });
        }

打印結(jié)果:

09-02 10:34:10.065 22364-22364/ruanrong.com.rxjava2demo D/tag: subscribe: main
09-02 10:34:10.067 22364-22364/ruanrong.com.rxjava2demo D/tag: accept: main

很明顯,發(fā)送和接受事件默認(rèn)都是在Main战得,也就是UI線程充边,那如何讓發(fā)送事件在子線程,跟新事件在UI線程呢常侦?這里引入一個(gè)新的概念浇冰,RxJava的線程調(diào)度器Scheduler,Schedulers內(nèi)部包含六中調(diào)度類型

  1. Schedulers.computation(?)
    用于計(jì)算任務(wù),如事件循環(huán)或和回調(diào)處理聋亡,不要用于IO操作(IO操作請(qǐng)使用Schedulers.io())肘习;默認(rèn)線程數(shù)等于處理器的數(shù)量
  2. Schedulers.from(executor)
    使用指定的Executor作為調(diào)度器
  3. Schedulers.immediate(?)
    在當(dāng)前線程立即開始執(zhí)行任務(wù)
  4. Schedulers.io(?)
    用于IO密集型任務(wù),如異步阻塞IO操作坡倔,這個(gè)調(diào)度器的線程池會(huì)根據(jù)需要增長(zhǎng)漂佩;對(duì)于普通的計(jì)算任務(wù),請(qǐng)使用Schedulers.computation()罪塔;Schedulers.io(?)默認(rèn)是一個(gè)CachedThreadScheduler仅仆,很像一個(gè)有線程緩存的新線程調(diào)度器
  5. Schedulers.newThread(?)
    為每個(gè)任務(wù)創(chuàng)建一個(gè)新線程
  6. Schedulers.trampoline(?)
    當(dāng)其它排隊(duì)的任務(wù)完成后,在當(dāng)前線程排隊(duì)開始執(zhí)行
    另外垢袱,還有一個(gè)特殊的調(diào)度類型:
AndroidSchedulers.mainThread() 該調(diào)度類型是唯一的確定發(fā)生在UI線程的

上面就是線程調(diào)度器的六中類型,都是Schedules類的靜態(tài)常量港柜。
接下來就是變身的時(shí)候了:

   Observable.create(new ObservableOnSubscribe<String >() {
            @Override
            public void subscribe(ObservableEmitter<String > e) throws Exception {
                Log.d(TAG, "subscribe: "+Thread.currentThread().getName());
                 e.onNext("hello world");
                 e.onComplete();
            }
          }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String >() {
            @Override
            public void accept(String  str) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
            }
        });
        }

打印結(jié)果:

09-02 10:59:12.717 12326-12357/ruanrong.com.rxjava2demo D/tag: subscribe: RxNewThreadScheduler-1
09-02 10:59:12.729 12326-12326/ruanrong.com.rxjava2demo D/tag: accept: main                                                             

果然请契,完成了事件發(fā)送在子線程,跟新在主線程的操作夏醉,下面將圖片的下載更新放到RxJava中來執(zhí)行:

 Observable.create(new ObservableOnSubscribe<Bitmap>() {
            @Override
            public void subscribe(ObservableEmitter<Bitmap> e) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
                Bitmap bmp = loadImage();
                 e.onNext(bmp);
                 e.onComplete();
            }
        }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Bitmap>() {
            @Override
            public void accept(Bitmap bitmap) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
                img.setImageBitmap(bitmap);
            }
        });

好了爽锥,圖片正常顯示,既然這樣畔柔,如果在onSubscribe和onObserver中多次指定線程呢氯夷?比如下面這樣:

      Observable.create(new ObservableOnSubscribe<String >() {
            @Override
            public void subscribe(ObservableEmitter<String > e) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
                e.onNext("hello world");
                e.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .observeOn(Schedulers.newThread())
                .subscribe(new Consumer<String >() {
            @Override
            public void accept(String  str) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
            }
        });
    }

打印結(jié)果:

09-02 11:09:51.315 21666-21686/? D/tag: subscribe: RxNewThreadScheduler-1
09-02 11:09:51.329 21666-21688/? D/tag: accept: RxNewThreadScheduler-2

可以說明設(shè)置訂閱事件選擇離它最近的線程調(diào)度方式,而觀察者選擇最后的線程調(diào)度方式靶擦。
既然完成了訂閱在子線程觀察在主線程腮考,那么對(duì)于這種在處理耗時(shí)任務(wù)過程中,Activity銷毀呢玄捕?這里就用到上一篇中的Disposiable對(duì)象了踩蔚,當(dāng)Activity銷毀時(shí)終止事件發(fā)送。

 Observable.create(new ObservableOnSubscribe<Bitmap>() {
            @Override
            public void subscribe(ObservableEmitter<Bitmap> e) throws Exception {
                Log.d(TAG, "accept: "+Thread.currentThread().getName());
                Bitmap bmp = loadImage();
                 e.onNext(bmp);
                 e.onComplete();
            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Bitmap>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        mDisposable = d;
                    }

                    @Override
                    public void onNext(Bitmap value) {
                        img.setImageBitmap(value);
                    }
                    @Override
                    public void onError(Throwable e) {
                    }
                    @Override
                    public void onComplete() {
                    }
                });

 @Override
    protected void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);
        if(!mDisposable.isDisposed()){
            mDisposable.dispose();
        }
    }

那如果有多個(gè)Disposable呢枚粘?這里有一個(gè)專門裝Disposable的容器類CompositeDisposable馅闽,里面維護(hù)了一個(gè)`OpenHashSet<Disposable> resources;集合,所以只需要在訂閱時(shí)將Disposable添加到CompositeDisposable中,在Activity銷毀時(shí)將該容器Clear掉就行了福也。
好了局骤,RxJava的事件調(diào)度就是這樣來改變事件執(zhí)行的線程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暴凑,一起剝皮案震驚了整個(gè)濱河市峦甩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搬设,老刑警劉巖穴店,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拿穴,居然都是意外死亡泣洞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門默色,熙熙樓的掌柜王于貴愁眉苦臉地迎上來球凰,“玉大人,你說我怎么就攤上這事腿宰∨凰撸” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵吃度,是天一觀的道長(zhǎng)甩挫。 經(jīng)常有香客問我,道長(zhǎng)椿每,這世上最難降的妖魔是什么伊者? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮间护,結(jié)果婚禮上亦渗,老公的妹妹穿的比我還像新娘。我一直安慰自己汁尺,他們只是感情好法精,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著痴突,像睡著了一般搂蜓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辽装,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天洛勉,我揣著相機(jī)與錄音,去河邊找鬼如迟。 笑死收毫,一個(gè)胖子當(dāng)著我的面吹牛攻走,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播此再,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼昔搂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了输拇?” 一聲冷哼從身側(cè)響起摘符,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎策吠,沒想到半個(gè)月后逛裤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猴抹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年带族,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟀给。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蝙砌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跋理,到底是詐尸還是另有隱情择克,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布前普,位于F島的核電站肚邢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拭卿。R本人自食惡果不足惜骡湖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望记劈。 院中可真熱鬧,春花似錦并巍、人聲如沸目木。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刽射。三九已至,卻和暖如春剃执,著一層夾襖步出監(jiān)牢的瞬間誓禁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工肾档, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摹恰,地道東北人辫继。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像俗慈,于是被迫代替她去往敵國(guó)和親姑宽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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