rxJava與Retrofit結(jié)合使用 基礎(chǔ)篇(1)

整理自:
http://blog.csdn.net/whuhan2013/article/details/51635653
http://gank.io/post/56e80c2c677659311bed9841


這篇文章從一個(gè)側(cè)面反映rxJava的優(yōu)越性,主要講解如何將rxJava與Retrofit2這兩個(gè)現(xiàn)在熱門的框架整合使用。
在看這篇文章之前,請(qǐng)先了解基本的rxJava和Retrofit2的知識(shí)


一、使用rxJava&Retrofit的好處

先讓我們看一下如果單純使用Retrofit會(huì)有什么問題:

  1. 復(fù)雜邏輯很難實(shí)現(xiàn):

比如:你的程序取到的 User 并不應(yīng)該直接顯示,而是需要先與數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行比對(duì)和修正后再顯示。使用 Callback 方式大概可以這么寫:

getUser(userId, new Callback<User>() {
    @Override
    public void success(User user) {
        processUser(user); // 嘗試修正 User 數(shù)據(jù)
        userView.setUser(user);
    }

    @Override
    public void failure(RetrofitError error) {
        // Error handling
        ...
    }
};

很簡(jiǎn)便,但不要這樣做。為什么?因?yàn)檫@樣做會(huì)影響性能。數(shù)據(jù)庫的操作很重,一次讀寫操作花費(fèi) 10~20ms 是很常見的,這樣的耗時(shí)很容易造成界面的卡頓。所以通常情況下,如果可以的話一定要避免在主線程中處理數(shù)據(jù)庫。所以為了提升性能,這段代碼可以優(yōu)化一下:

getUser(userId, new Callback<User>() {
    @Override
    public void success(User user) {
        new Thread() {
            @Override
            public void run() {
                processUser(user); // 嘗試修正 User 數(shù)據(jù)
                runOnUiThread(new Runnable() { // 切回 UI 線程
                    @Override
                    public void run() {
                        userView.setUser(user);
                    }
                });
            }).start();
    }

    @Override
    public void failure(RetrofitError error) {
        // Error handling
        ...
    }
};

性能問題解決,但……這代碼實(shí)在是太亂了,迷之縮進(jìn)?。‰s亂的代碼往往不僅僅是美觀問題,因?yàn)榇a越亂往往就越難讀懂,而如果項(xiàng)目中充斥著雜亂的代碼,無疑會(huì)降低代碼的可讀性,造成團(tuán)隊(duì)開發(fā)效率的降低和出錯(cuò)率的升高。
這時(shí)候,如果用 RxJava 的形式,就好辦多了。 RxJava 形式的代碼是這樣的:

getUser(userId)
    .doOnNext(new Action1<User>() {
        @Override
        public void call(User user) {
            processUser(user);
        })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<User>() {
        @Override
        public void onNext(User user) {
            userView.setUser(user);
        }

        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable error) {
            // Error handling
            ...
        }
    });

代碼中oOnNext()的執(zhí)行在onNext()之前,對(duì)數(shù)據(jù)進(jìn)行相關(guān)處理。doOnNext具體的使用方法不是本文討論的重點(diǎn)。

  1. ProgressDialog的show方法應(yīng)該在哪調(diào)用:

這個(gè)問題如果不用rxJava,解決起來也很容易:只要在調(diào)用Retrofit之前寫一遍show()的代碼,但是這樣不容易操控整個(gè)網(wǎng)絡(luò)請(qǐng)求的邏輯(這個(gè)我沒嘗試過,暫時(shí)這么認(rèn)為)。但是這個(gè)如果用rxJava解決的話就很簡(jiǎn)單,不在這里單講了,可以看下面的代碼。

二、在Retrofit上添加rxJava

  1. 添加Rxjava:
    先在Gradle中添加依賴。
    接著在創(chuàng)建Retrofit的過程中添加如下代碼:
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

注意第四行,這樣一來我們定義的service返回值就不在是一個(gè)Call了,而是一個(gè)Observable

  1. 修改接口:
public interface MovieService {
    @GET("top250")
    Observable<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);
}
  1. 修改getMovie:
//進(jìn)行網(wǎng)絡(luò)請(qǐng)求
private void getMovie(){
    String baseUrl = "https://api.douban.com/v2/movie/";

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();

    MovieService movieService = retrofit.create(MovieService.class);

    movieService.getTopMovie(0, 10)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<MovieEntity>() {
                @Override
                public void onCompleted() {
                    Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onError(Throwable e) {
                    resultTV.setText(e.getMessage());
                }

                @Override
                public void onNext(MovieEntity movieEntity) {
                    resultTV.setText(movieEntity.toString());
                }
            });
}

三、封裝上述代碼

創(chuàng)建一個(gè)對(duì)象HttpMethods

public class HttpMethods {

    public static final String BASE_URL = "https://api.douban.com/v2/movie/";

    private static final int DEFAULT_TIMEOUT = 5;

    private Retrofit retrofit;
    private MovieService movieService;

    //構(gòu)造方法私有
    private HttpMethods() {
        //手動(dòng)創(chuàng)建一個(gè)OkHttpClient并設(shè)置超時(shí)時(shí)間
        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        retrofit = new Retrofit.Builder()
                .client(httpClientBuilder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

        movieService = retrofit.create(MovieService.class);
    }

    //在訪問HttpMethods時(shí)創(chuàng)建單例
    private static class SingletonHolder{
        private static final HttpMethods INSTANCE = new HttpMethods();
    }

    //獲取單例
    public static HttpMethods getInstance(){
        return SingletonHolder.INSTANCE;
    }

    /**
     * 用于獲取豆瓣電影Top250的數(shù)據(jù)
     * @param subscriber 由調(diào)用者傳過來的觀察者對(duì)象
     * @param start 起始位置
     * @param count 獲取長(zhǎng)度
     */
    public void getTopMovie(Subscriber<MovieEntity> subscriber, int start, int count){
        movieService.getTopMovie(start, count)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

用一個(gè)單例來封裝該對(duì)象,在構(gòu)造方法中創(chuàng)建Retrofit和對(duì)應(yīng)的Service。 如果需要訪問不同的基地址,那么你可能需要?jiǎng)?chuàng)建多個(gè)Retrofit對(duì)象,或者干脆根據(jù)不同的基地址封裝不同的HttpMethod類。
我們回頭再來看MainActivity中的getMovie方法:

private void getMovie(){
     subscriber = new Subscriber<MovieEntity>() {
         @Override
         public void onCompleted() {
             Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();
         }

         @Override
         public void onError(Throwable e) {
             resultTV.setText(e.getMessage());
         }

         @Override
         public void onNext(MovieEntity movieEntity) {
             resultTV.setText(movieEntity.toString());
         }
     };
     HttpMethods.getInstance().getTopMovie(subscriber, 0, 10);
}        

其中subscriber是MainActivity的成員變量。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我從去年開始使用 RxJava ,到現(xiàn)在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy閱讀 5,759評(píng)論 7 62
  • 前言RxJava和Retrofit也火了一段時(shí)間了,不過最近一直在學(xué)習(xí)ReactNative和Node相關(guān)的姿勢(shì),...
    AFinalStone閱讀 628評(píng)論 0 0
  • Retrofit 是 Square 的一個(gè)著名的網(wǎng)絡(luò)請(qǐng)求庫。沒有用過 Retrofit 的可以選擇跳過這一小節(jié)也沒...
    腦袋君閱讀 783評(píng)論 0 8
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,551評(píng)論 19 139
  • 今天組織了大家26去玩,感覺還是比較成功的。公司結(jié)算績(jī)效,我沒有績(jī)效,我感覺挺難達(dá)標(biāo)的。
    青玄子閱讀 332評(píng)論 0 0

友情鏈接更多精彩內(nèi)容