RxJava 初探(網絡請求)

RxJava 介紹


寫在前面

rxjava 也用了好多次了。時隔多年,才終於有勇氣挖一下它的源碼。
這次主要研究了發佈訂閱流程 subscribe() 以及核心變換 lift(),至於其他的像線程切換 Schedulers、豐富的操作符啊,都有待研究。
之後可能會再更新幾篇,也可能就太監了。。。
1.RxJava 源碼分析之 —— lift 變換


What is RxJava?

RxJava 的思想是響應式編程,這是一種事件驅動的編程模式。事件驅動很熟悉吧,經典如通過 Listener 來監聽點擊事件再回調 OnClick(),這種方式早就爛大街了吧。RxJava 本質上與這種監聽器沒有區別,那麼它又有什麼獨到之處呢?


Why RxJava?

它的獨到之處在與它響應式的編程思想——一切皆抽象爲事件。如果說對於點擊事件,Android 本身已經提供了一套監聽方案,那麼網絡請求呢,文件讀寫呢,還有數不清的事件呢。。此前,我們都是自己編寫網絡請求框架,然後對外提供回調接口 OnSuccess() 、OnFail()。換成文件讀寫,又得重新搞一套框架,我們累了,需要一個通用的解決方案,它就是 RxJava 。
By the way,解決了”回調地獄”只是順帶的好處罷了。


Where RxJava?

那麼什麼場景下使用它呢?
它的應用場合很多,本文將以網絡請求爲例做一個 Demo。

更多場景請參考這篇文章:
可能是東半球最全的RxJava使用場景小結


How RxJava?

要使用 RxJava 還得深入到代碼層面。
它是基於觀察者模式實現的,那麼自然會有一個被觀察者(可觀察的對象) Observable 和 一個觀察者(訂閱者)Subscriber。


需要的第三方包

// app/build.gradle
dependencies {
    // 。。。

    // rxjava
    compile 'io.reactivex:rxjava:1.0.14'
    compile 'io.reactivex:rxandroid:1.1.0'

    // rxlifecycle
    compile 'com.trello:rxlifecycle:0.4.0'
    compile 'com.trello:rxlifecycle-components:0.4.0'
    // 上面4個包是必要的

    // okhttp
    compile 'com.squareup.okhttp:okhttp:2.7.2'

    // butterknife 
    compile 'com.jakewharton:butterknife:7.0.1'
}

最好配合上 retrolambda 這個插件,用 lambda 語法寫起來才爽。

概念介紹

先來看一下 Subscriber 包含了哪些東西

// 打開源碼我們看到 Subsctiber 實現了 Observer
public abstract class Subscriber<T> implements Observer<T>, Subscription { ... }

// 而 Observer 包含有一些回調函數
// {OnNext(), OnError(), OnComplete()}
public interface Observer<T> {
    void onNext(T t);
    void onError(Throwable e);
    void onCompleted();
}

然後看看它怎麼訂閱事件

// Subscriber 作爲監聽器,需要註冊到 Observable 中:
// (我們才能在 Observable 中回調它的一些函數)
mObservable.subscribe(mSubscriber);

// 這類似於我們註冊點擊事件的監聽:
mView.setOnClickListener(mOnClickListener);

// 可以對應起來理解,View 即是被觀察者,
// 而 OnClickListener 則是訂閱者。

其中,mSubscriber 是這樣的

// 當然,正如 mOnClickListener 實現了 OnClick(),
// mSubscriber 作爲匿名類實現了三個接口函數,像這樣:
Subscriber<String> mSubscriber = new Subscriber<String>() {  
    @Override  
    public void onNext(String s) { }  

    @Override  
    public void onCompleted() { }  

    @Override  
    public void onError(Throwable e) { }  
};  

一些簡化寫法:

// 考慮到這樣的匿名類寫法比較冗長,而且不能用 lambda 簡化,
// 作者還提供了 subscribe(mSubscriber) 的一些重載版本:
mObservable.subscribe(onNext);
mObservable.subscribe(onNext, onError);
mObservable.subscribe(onNext, onError, onComplete);
// 太棒了,它們都是函數式接口,可以用 lambda 簡化代碼。


再來看一下 Observable , 之前說到它可以被 Subcriber 訂閱。但是在此之前,我們需要先創建它。

// 創建 Observable 實例
mObservable.create(mOnSubscribe); 

// 其中 mOnSubscribe 接口,用來制定事件分發的流程。
// 即按照一定順序,回調之前註冊好的三個函數: 
// {OnNext(), OnError(), OnComplete()}
Observable.OnSubscribe<String> mOnSubscribe = new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        String data = getData(); // 獲取數據: 網絡任務或是別的...
        if(data == null){ // 獲取失敗
            subscriber.onError(new Throwable("data 爲空"));
            subscriber.onCompleted();
        }else{ // 獲取成功
            subscriber.onNext(data);
            subscriber.onCompleted();
        }
    }
};

What’s more,Observable 還可以分別指定 Observable 和 Subcriber 的線程:

Observable.create(subscriber -> {})
    .subscribeOn(Schedulers.io()) // 指定 Observable 的線程 ———— 主線程。
    .observeOn(AndroidSchedulers.mainThread()); // 指定 Subscriber 的線程 ———— io 線程。

框架內部估計封裝了線程切換的功能,這在 Android 的多線程環境中,極大地簡化了線程操作。

實踐

我們來試一下網絡請求吧,從網上拉取一段字符串(http://publicobject.com/helloworld.txt)。首先,我們把一個請求看作一個事件,先創建一個事件對應的被觀察者 NetworkObserable.getInstance() : Observable< String >。

public class NetworkObserable{
    ...
    // 獲取一個 Observable 實例
    public static Observable<String> getInstance() {
        return Observable.create((Observable.OnSubscribe<String>)
                subscriber -> subscribeData(subscriber, NetworkHelper.getData(NetworkHelper.GET))
                // getData()發起一個GET請求,返回 String 數據。
            ).subscribeOn(Schedulers.io());  
            // 被觀察的對象在 io 線程進行網絡請求,也可以自己新開一個線程
    }

    // 取得網絡數據後,回調 subscriber 的一些函數,在界面上顯示這些數據
    private static void subscribeData(Subscriber<? super String> subscriber, String data){
        if(data == null){
            subscriber.onError(new Throwable("data 爲空"));
            subscriber.onCompleted();
        }else{
            subscriber.onNext(data);
            subscriber.onCompleted();
        }
    }
}

在點擊按鈕的時候訂閱這個事件。

@OnClick(R.id.btn_GET) public void onClick() {
    NetworkObservable.getInstance()                 // 獲取 Observable 實例
        .compose(this.<String>bindToLifecycle())    // Rxlifecycle, 綁定到 Activity 的生命週期。
        .observeOn(AndroidSchedulers.mainThread())  // 指定觀察者的線程————主線程。
        .subscribe(                                 // 訂閱事件
            // onNext, 請求成功
            data -> mTvResult.setText(data),
            // onError, 請求失敗
            throwable -> Toast.makeText(this, throwable.getMessage(), Toast.LENGTH_SHORT).show()
        );
}

然後,沒有然後了。。。


附錄

按照慣例,放上 Demo 地址,有興趣可以下載一下:
https://github.com/fashare2015/my_rxjava_demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章