Android 优雅的让RxJava2.0+Retrofit2.0结合使用

来源:互联网 发布:公章制作软件apk 编辑:程序博客网 时间:2024/06/06 00:58

转载自:http://blog.csdn.net/demonliuhui/article/details/77868677



前言

本文参考:

RxJava 与 Retrofit 结合的最佳实践http://gank.io/post/56e80c2c677659311bed9841

与上文不同的是:

  1. 本文采用最新的RxJava2.0与Retrifit2.0来实现,并针对于1.x不同的地方进行处理。
  2. 针对请求过程进行的封装,额外增加缓存策略和请求头部处理。
  3. RxJava2.0使用笔记:http://blog.csdn.net/demonliuhui/article/details/77848691
  4. Retrifit2.0使用笔记:http://blog.csdn.net/demonliuhui/article/details/77854530

使用配置

添加依赖

dependencies {    ...    compile 'io.reactivex.rxjava2:rxjava:2.1.3'    compile 'com.squareup.retrofit2:retrofit:2.3.0'    compile 'com.squareup.retrofit2:converter-gson:2.3.0'    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'    compile 'com.squareup.okhttp3:okhttp:3.9.0'    compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'    compile 'com.squareup.retrofit2:converter-scalars:2.3.0'    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意:

  1. 添加RxAndroid是为了解决线程调度问题。
  2. okhttp3:logging-interceptor是为了配置缓存策略,必须跟okhttp同一版本号,否则会报错:Failed resolution of: Lokhttp3/internal/Platform
  3. converter-scalars 用于将请求结果转换为基本类型,一般为String
  4. converter-gson 用于将请求结果转换为实体类型

添加权限

<uses-permission android:name="android.permission.INTERNET"/>    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  • 1
  • 2

测试Api

豆瓣电影的Top250做测试连接,目标地址为:

https://api.douban.com/v2/movie/top250?start=0&count=10

返回的数据格式,大家自己访问下链接就看到了。

创建数据实体类

知道数据格式后我们创建对应数据实体类,方便处理获取后的数据。 
这里只是简单获取几个数据,大家可以根据自己需求去编写自己想要的数据。

public class Movie {    private String title;    private List<Subjects> subjects;    public String getTitle() {        return title;    }    public List<Subjects> getSubjects() {        return subjects;    }}public class Subjects {    private String title, year, id;    public Subjects(String title, String year, String id) {        this.title = title;        this.year = year;        this.id = id;    }    public String getTitle() {        return title;    }    public String getYear() {        return year;    }    public String getId() {        return id;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

最基本的RxJava+Retrofit

1.创建Service类

因为要结合使用RxJava,所以返回值就不在是一个Call了,而是一个Observable。

public interface ApiService {    @GET("top250")    Observable<Movie> getTopMovie(@Query("start") int start, @Query("count") int count);}
  • 1
  • 2
  • 3
  • 4

2.创建Retrofit请求过程

  String baseUrl = "https://api.douban.com/v2/movie/"; Retrofit retrofit = new Retrofit.Builder()                .baseUrl(baseUrl)               .addConverterFactory(ScalarsConverterFactory.create())//请求结果转换为基本类型                .addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())  //适配RxJava2.0, RxJava1.x则为RxJavaCallAdapterFactory.create()                .build();        apiService = retrofit.create(ApiService.class);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3.Activity发出请求(RxJava订阅)及处理数据

注意:RxJava2.0开始subscribe的对象不能是Subscriber,只能是Observer和Consumer,为了处理完整的过程我们这里选择Observer。 onSubscribe等同于onStart。

apiService.getTopMovie(0, 10)                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Observer<Movie>() {                    @Override                    public void onSubscribe(Disposable d) {                        Log.d(TAG, "onSubscribe: ");                    }                    @Override                    public void onNext(Movie movie) {                        Log.d(TAG, "onNext: " + movie.getTitle());                        List<Subjects> list = movie.getSubjects();                        for (Subjects sub : list) {                            Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());                        }                    }                    @Override                    public void onError(Throwable e) {                        Log.e(TAG, "onError: " + e.getMessage());                    }                    @Override                    public void onComplete() {                        Log.d(TAG, "onComplete: Over!");                    }                });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

4.运行结果

09-06 14:25:09.151 30008-30008/eee.rxjavaretrofit D/MainActivity: onSubscribe: 09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top25009-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬09-06 14:25:11.308 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间09-06 14:25:11.309 30008-30008/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员09-06 14:25:11.311 30008-30008/eee.rxjavaretrofit D/MainActivity: onComplete: Over!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这样就完成了最基本的RxJava+Retrofit,结果也与预期一致。 
但是这样显然不能让我们去优雅的使用。毕竟优雅的复用已写过的代码才是我们的追求。 
因此我们需要进一步对刚才的代码进行封装。

基本的封装RxJava+Retrofit

1.封装Retrofit请求过程

在之前的代码的基础上,创建Api.java用于封装Retrofit,代码如下:

public class Api {    public static String baseUrl = "https://api.douban.com/v2/movie/";    public static ApiService apiService;    //单例    public static ApiService getApiService() {        if (apiService == null) {            synchronized (Api.class) {                if (apiService == null) {                    new Api();                }            }        }        return apiService;    }    private Api() {        Retrofit retrofit = new Retrofit.Builder()                .baseUrl(baseUrl)                .addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类                //适配RxJava2.0,RxJava1.x则为RxJavaCallAdapterFactory.create()                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())                .build();        apiService = retrofit.create(ApiService.class);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

2.封装线程管理和订阅

在使用RxJava的过程中,每次都重复写线程管理和订阅代码也是一件繁琐的事情。 
创建ApiMethods用于封装线程管理和订阅的过程及调用请求。如下:

public class ApiMethods {    /**     * 封装线程管理和订阅的过程     */    public static void ApiSubscribe(Observable observable, Observer observer) {        observable.subscribeOn(Schedulers.io())                .unsubscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(observer);    }    /**     * 用于获取豆瓣电影Top250的数据     *     * @param observer 由调用者传过来的观察者对象     * @param start    起始位置     * @param count    获取长度     */    public static void getTopMovie(Observer<Movie> observer, int start, int count) {        ApiSubscribe(Api.getApiService().getTopMovie(start, count), observer);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3.Activity中调用及处理数据

 Observer<Movie> observer = new Observer<Movie>() {            @Override            public void onSubscribe(Disposable d) {                  Log.d(TAG, "onSubscribe: ");            }            @Override            public void onNext(Movie movie) {                Log.d(TAG, "onNext: " + movie.getTitle());                List<Subjects> list = movie.getSubjects();                for (Subjects sub : list) {                    Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());                }            }            @Override            public void onError(Throwable e) {                Log.e(TAG, "onError: " + e.getMessage());            }            @Override            public void onComplete() {                Log.d(TAG, "onComplete: Over!");            }        };        ApiMethods.getTopMovie(observer, 0, 10);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

4.测试结果

09-06 15:14:01.413 16819-16819/eee.rxjavaretrofit D/MainActivity: onSubscribe: 09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top25009-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员09-06 15:14:02.465 16819-16819/eee.rxjavaretrofit D/MainActivity: onComplete: Over!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

经过两次封装,如果有新的Api接口我们只需要在ApiService类中增加对应的接口方法,然后在ApiMethods类中写对应的请求方法即可。与基本的RxJava+Retrofit相比,在额外代码量和易用性上都明显占优。

进一步封装RxJava+Retrofit

看完上一步,你还是肯定还是会觉得,在Activity每次处理订阅返回的数据的时候都要实例化一个Observer对象,然后重写onSubscribe,onNext,onError,onComplete四个方法。虽然Android Studio一键就能补全代码,我们只用简单处理一下就ok了。但是那么多代码堆在那里还是让人不爽的。 
因此我们进一步针对Observer进行封装。 
针对重写方法的封装最好的方法就是使用接口+implements/继承的方式实现。 
仔细分析会发现,其实除了onNext涉及数据处理,其余三个方法都可以进行模板化处理,比如显示一个Toast,输出错误信息等;当然如果你的业务需要,也可以按照onNext特别处理。 
在之前代码的基础上。

1.新建监听接口

使用通配泛型,适用于所有类型的数据。

public interface ObserverOnNextListener<T> {    void onNext(T t);}
  • 1
  • 2
  • 3

2.重写Observer

public class MyObserver<T> implements Observer<T> {    private static final String TAG = "MyObserver";    private ObserverOnNextListener listener;    private Context context;    public MyObserver(Context context, ObserverOnNextListener listener) {        this.listener = listener;        this.context = context;    }    @Override    public void onSubscribe(Disposable d) {        Log.d(TAG, "onSubscribe: ");        //添加业务处理    }    @Override    public void onNext(T t) {        listener.onNext(t);    }    @Override    public void onError(Throwable e) {        Log.e(TAG, "onError: ", e);        //添加业务处理    }    @Override    public void onComplete() {        Log.d(TAG, "onComplete: ");        //添加业务处理    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

3.Activity中使用

 ObserverOnNextListener<Movie> listener = new ObserverOnNextListener<Movie>() {            @Override            public void onNext(Movie movie) {                Log.d(TAG, "onNext: " + movie.getTitle());                List<Subjects> list = movie.getSubjects();                for (Subjects sub : list) {                    Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());                }            }        };        ApiMethods.getTopMovie(new MyObserver<Movie>(this, listener), 0, 10);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4.测试结果

09-06 16:01:59.918 3487-3487/eee.rxjavaretrofit D/MyObserver: onSubscribe: 09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top25009-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间09-06 16:02:00.717 3487-3487/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员09-06 16:02:00.718 3487-3487/eee.rxjavaretrofit D/MyObserver: onComplete: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

优雅的封装RxJava+Retrofit

上面的代码可谓是封装的彻底了,但是还不够优雅。 
如何优雅? 
网络请求一般都是耗时的,我们需要在进行网络请求的时候有一个进度框,增加用户体验。 
根据上一步,我们只需要将进度框show在onSubscribe中,然后在onError/onComplete里cancel掉就行了。如果用户取消关闭了进度框,那么也随之取消了当前的Http请求。

1.编写ProgressDialog类代码

Handler接收两个消息来控制显示Dialog还是关闭Dialog。

public class ProgressDialogHandler extends Handler {    public static final int SHOW_PROGRESS_DIALOG = 1;    public static final int DISMISS_PROGRESS_DIALOG = 2;    private ProgressDialog pd;    private Context context;    private boolean cancelable;    private ProgressCancelListener mProgressCancelListener;    public ProgressDialogHandler(Context context, ProgressCancelListener            mProgressCancelListener, boolean cancelable) {        super();        this.context = context;        this.mProgressCancelListener = mProgressCancelListener;        this.cancelable = cancelable;    }    private void initProgressDialog() {        if (pd == null) {            pd = new ProgressDialog(context);            pd.setCancelable(cancelable);            if (cancelable) {                pd.setOnCancelListener(new DialogInterface.OnCancelListener() {                    @Override                    public void onCancel(DialogInterface dialogInterface) {                        mProgressCancelListener.onCancelProgress();                    }                });            }            if (!pd.isShowing()) {                pd.show();            }        }    }    private void dismissProgressDialog() {        if (pd != null) {            pd.dismiss();            pd = null;        }    }    @Override    public void handleMessage(Message msg) {        switch (msg.what) {            case SHOW_PROGRESS_DIALOG:                initProgressDialog();                break;            case DISMISS_PROGRESS_DIALOG:                dismissProgressDialog();                break;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

此处安全按照参考文章来写的,当然你也可以直接ProgressDialog dialog = new ProgressDialog(context);

2.编写监听取消的接口类

public interface ProgressCancelListener {    void onCancelProgress();}
  • 1
  • 2
  • 3
  • 4

3.在MyObserver中添加ProgressDialog

将上面ProgressDialog在Observer中初始化,并在相应的位置进行显示和隐藏。

public class ProgressObserver<T> implements Observer<T>, ProgressCancelListener {    private static final String TAG = "ProgressObserver";    private ObserverOnNextListener listener;    private ProgressDialogHandler mProgressDialogHandler;    private Context context;    private Disposable d;   public ProgressObserver(Context context, ObserverOnNextListener listener) {        this.listener = listener;        this.context = context;        mProgressDialogHandler = new ProgressDialogHandler(context, this, true);    }    private void showProgressDialog() {        if (mProgressDialogHandler != null) {            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget();        }    }    private void dismissProgressDialog() {        if (mProgressDialogHandler != null) {            mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG)                    .sendToTarget();            mProgressDialogHandler = null;        }    }    @Override    public void onSubscribe(Disposable d) {        this.d = d;        showProgressDialog();    }    @Override    public void onNext(T t) {        listener.onNext(t);    }    @Override    public void onError(Throwable e) {        dismissProgressDialog();        Log.e(TAG, "onError: ", e);    }    @Override    public void onComplete() {        dismissProgressDialog();        Log.d(TAG, "onComplete: ");    }    @Override    public void onCancelProgress() {         //如果处于订阅状态,则取消订阅        if (!d.isDisposed()) {            d.dispose();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

5.Activity中使用

 ObserverOnNextListener<Movie> listener = new ObserverOnNextListener<Movie>() {            @Override            public void onNext(Movie movie) {                Log.d(TAG, "onNext: " + movie.getTitle());                List<Subjects> list = movie.getSubjects();                for (Subjects sub : list) {                    Log.d(TAG, "onNext: " + sub.getId() + "," + sub.getYear() + "," + sub.getTitle());                }            }        };       ApiMethods.getTopMovie(new ProgressObserver<Movie>(this, listener), 0, 10);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

6.测试结果

09-06 16:32:05.135 6823-6823/eee.rxjavaretrofit D/ProgressObserver: onSubscribe: 09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 豆瓣电影Top25009-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292052,1994,肖申克的救赎09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1291546,1993,霸王别姬09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1295644,1994,这个杀手不太冷09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292720,1994,阿甘正传09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292063,1997,美丽人生09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1291561,2001,千与千寻09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1295124,1993,辛德勒的名单09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 1292722,1997,泰坦尼克号09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 3541415,2010,盗梦空间09-06 16:32:05.990 6823-6823/eee.rxjavaretrofit D/MainActivity: onNext: 2131459,2008,机器人总动员09-06 16:32:05.992 6823-6823/eee.rxjavaretrofit D/ProgressObserver: onComplete: 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

优化Retrofit,设置缓存,超时策略

使用OkHttpClient对Retrofit设置设置缓存,超时策略。

public class ApiStrategy {    public static String baseUrl = "https://api.douban.com/v2/movie/";    //读超时长,单位:毫秒    public static final int READ_TIME_OUT = 7676;    //连接时长,单位:毫秒    public static final int CONNECT_TIME_OUT = 7676;    public static ApiService apiService;    public static ApiService getApiService() {        if (apiService == null) {            synchronized (Api.class) {                if (apiService == null) {                    new ApiStrategy();                }            }        }        return apiService;    }    private ApiStrategy() {        HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();        logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);        //缓存        File cacheFile = new File(MyApplication.getContext().getCacheDir(), "cache");        Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb        //增加头部信息        Interceptor headerInterceptor = new Interceptor() {            @Override            public Response intercept(Chain chain) throws IOException {                Request build = chain.request().newBuilder()                        //.addHeader("Content-Type", "application/json")//设置允许请求json数据                        .build();                return chain.proceed(build);            }        };        //创建一个OkHttpClient并设置超时时间        OkHttpClient client = new OkHttpClient.Builder()                .readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS)                .connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS)                .addInterceptor(mRewriteCacheControlInterceptor)                .addNetworkInterceptor(mRewriteCacheControlInterceptor)                .addInterceptor(headerInterceptor)                .addInterceptor(logInterceptor)                .cache(cache)                .build();        Retrofit retrofit = new Retrofit.Builder()                .client(client)                .baseUrl(baseUrl)                .addConverterFactory(GsonConverterFactory.create())//请求的结果转为实体类                //适配RxJava2.0,RxJava1.x则为RxJavaCallAdapterFactory.create()                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())                .build();        apiService = retrofit.create(ApiService.class);    }    /**     * 设缓存有效期为两天     */    private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2;    /**     * 云端响应头拦截器,用来配置缓存策略     * Dangerous interceptor that rewrites the server's cache-control header.     */    private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() {        @Override        public Response intercept(Chain chain) throws IOException {            Request request = chain.request();            String cacheControl = request.cacheControl().toString();            if (!NetWorkUtils.isNetConnected(MyApplication.getContext())) {                request = request.newBuilder()                        .cacheControl(TextUtils.isEmpty(cacheControl) ? CacheControl                                .FORCE_NETWORK : CacheControl.FORCE_CACHE)                        .build();            }            Response originalResponse = chain.proceed(request);            if (NetWorkUtils.isNetConnected(MyApplication.getContext())) {                return originalResponse.newBuilder()                        .header("Cache-Control", cacheControl)                        .removeHeader("Pragma")                        .build();            } else {                return originalResponse.newBuilder()                        .header("Cache-Control", "public, only-if-cached, max-stale=" +                                CACHE_STALE_SEC)                        .removeHeader("Pragma")                        .build();            }        }    };}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

总结

目前为止,就封装完毕了。 
现在我们再写一个新的网络请求,步骤是这样的:

  1. 在Service中定义一个新的方法。
  2. 在ApiMethods封装对应的请求(代码基本可以copy)
  3. 创建一个ObserverOnNextListener处理请求数据。
  4. 在onNext处理业务逻辑。