美文网首页androidAndroidAndroid
Retrofit+RxJava+OkHttp链式封装

Retrofit+RxJava+OkHttp链式封装

作者: 愚蠢的高小星 | 来源:发表于2016-11-12 22:47 被阅读4173次

    最近公司要开始新项目,准备换掉之前的网络框架。正好最近在看Retrofit+RxJava,感觉还是非常好用的,于是准备将网络框架替换为Retrofit+RxJava+OkHttp。
    Retrofit+RxJava的优点很明显:可以实现线程之间的快速切换;处理数据简洁易懂,易于进行元素间的变换;可以简单处理大量的嵌套异步回调等。但是使用Retrofit+RxJava+OkHttp完成一次网络请求还是需要写很多代码的,所以肯定是需要再次封装的。这里我根据项目的特点对Retrofit+RxJava+OkHttp进行了封装,优点是调用方便,代码量少,链式结构清晰。当然,本文只是提供了一种封装方式,只有适合自己项目的封装才是最好的封装~

    关于Retrofit+RxJava的基本用法,本文不作详细介绍,可以参考
    Retrofit官方文档
    给 Android 开发者的 RxJava 详解

    先来看一下调用的代码:

        private void doHttpRequest() {
            HttpManager.getInstance()
                    .with(this)
                    .setObservable(RetrofitManager.getService().getExpress("yuantong", "200382770316"))
                    .setDataListener(new HttpDataListener<List<Express>>() {
                        @Override
                        public void onNext(List<Express> list) {
                            //这里对返回数据进行处理
                        }
                    });
        }
    
    

    怎么样,是不是很简单┑( ̄Д  ̄)┍ 几行代码就完成了一次网络请求,使用时只需要传递上下文Context、向接口传递的参数以及返回数据的类型,就可以直接对数据进行处理了!

    下面来看一下封装的过程和思路:
    常见的接口返回数据的格式一般是这个样子的

    {
        "status": 200,
        "message": "success",
        "data": {
            //具体的业务数据
         }
    }
    

    我们希望的封装是这样的:对status和判断和message的处理进行封装,在调用时,我们只关心请求成功后返回的数据,只需要在请求成功后对返回的对象进行处理,而请求失败或者其他情况全部进行封装,不在调用时处理。

    测试使用的是快递100的测试接口:
    http://www.kuaidi100.com/query?type=yuantong&postid=200382770316

    来看一下代码~首先是build.gradle文件:

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        compile 'com.android.support:appcompat-v7:23.1.1'
        compile 'io.reactivex.rxjava2:rxjava:2.0.1'
        compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    
        compile 'com.squareup.retrofit2:retrofit:2.0.1'
        compile 'com.squareup.retrofit2:converter-gson:2.0.1'
        compile 'com.squareup.retrofit2:adapter-rxjava2:+'
        compile 'com.google.code.gson:gson:2.2.4'
        compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
    }
    
    

    引入了Retrofit、RxJava、RxAndroid、OkHttp等相关库。

    然后是Retrofit的管理类:

    public class RetrofitManager {
    
        public static final String url = "http://www.kuaidi100.com/";
        private static final int TIMEOUT = 15;
        private HttpService httpService;
        private volatile static RetrofitManager singleton;
        private boolean debugMode;
    
        private RetrofitManager() {
            //OkHttp初始化
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
            //debug模式打印网络请求日志
            if (debugMode){
                HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
                logging.setLevel(HttpLoggingInterceptor.Level.BODY);
                builder.addInterceptor(logging);
            }
    
            //Retrofit初始化
            Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(url)
                .build();
            httpService = retrofit.create(HttpService.class);
        }
    
        public static RetrofitManager getInstance() {
            if (singleton == null) {
                synchronized (RetrofitManager.class) {
                    if (singleton == null) {
                        singleton = new RetrofitManager();
                    }
                }
            }
            return singleton;
        }
    
        public static HttpService getService(){
            return getInstance().httpService;
        }
    }
    
    

    Retrofit本身不具备http标准网络访问基础,所以还是需要依赖OkHttp进行网络访问。在RetrofitManager类中对OkHttp和Retrofit进行了初始化,同时实例化一个HttpService对象。

    HttpService:

    public interface HttpService {
    
        @GET("query")
        Observable<ResultModel<List<Express>>> getExpress(@Query("type") String type,
                                                          @Query("postid") String postid);
    }
    

    我们知道,RxJava的基本实现是Observable.subscribe(Observer),通过以上代码我们可以创建出一个Observable对象。那么接下来就需要封装出一个Observer。

    返回结果的基础类,统一处理status和message

    public class ResultModel<T> {
    
        private String status;//200成功
        private String message;
        private T data;
    }
    

    转换类,利用RxJava的map方法,对ResultModel进行处理后转换为业务实体类

    public class ResultMap<T> implements Function<ResultModel<T>, T> {
    
      @Override
      public T apply(ResultModel<T> httpResult) {
        if ("200".equals(httpResult.getStatus())) {
          return httpResult.getData();
        } else {
          throw new RuntimeException("请求失败(code=" + httpResult.getStatus() + ",message=" + httpResult.getMessage() + ")");
        }
      }
    }
    
    

    Observer封装,显示一个ProgressDialog,同时在请求失败时在OnError回调方法中对错误信息进行处理,在请求成功OnNext回调方法中交给调用者处理。

    public class HttpObserver<T> implements Observer<T> {
    
        private HttpDataListener mSubscriberOnNextListener;
        private WeakReference<Context> context;
        private ProgressDialog dialog;
    
        public HttpObserver(HttpDataListener mSubscriberOnNextListener, Context context) {
            this.mSubscriberOnNextListener = mSubscriberOnNextListener;
            this.context = new WeakReference<>(context);
            initProgressDialog();
        }
    
        //自定义ProgressDialog提示文字
        public HttpObserver(HttpDataListener mSubscriberOnNextListener, Context context, String message) {
            this.mSubscriberOnNextListener = mSubscriberOnNextListener;
            this.context = new WeakReference<>(context);
            initProgressDialog(message);
        }
    
        //自定义ProgressDialog
        public HttpObserver(HttpDataListener mSubscriberOnNextListener, Context context, ProgressDialog dialog) {
            this.mSubscriberOnNextListener = mSubscriberOnNextListener;
            this.context = new WeakReference<>(context);
            this.dialog = dialog;
        }
    
        private void initProgressDialog() {
            Context context = this.context.get();
            if (dialog == null && context != null) {
                dialog = new ProgressDialog(context);
                dialog.setMessage("加载中……");
                dialog.setCancelable(false);
            }
        }
    
        private void initProgressDialog(String message) {
            Context context = this.context.get();
            if (dialog == null && context != null) {
                dialog = new ProgressDialog(context);
                dialog.setMessage(message);
                dialog.setCancelable(false);
            }
        }
    
        private void showProgressDialog() {
            Context context = this.context.get();
            if (dialog == null || context == null) return;
            if (!dialog.isShowing()) {
                dialog.show();
            }
        }
    
        private void dismissProgressDialog() {
            if (dialog != null && dialog.isShowing()) {
                dialog.dismiss();
            }
        }
    
        @Override
        public void onSubscribe(Disposable d) {
            showProgressDialog();
        }
    
        @Override
        public void onComplete() {
            dismissProgressDialog();
        }
    
        @Override
        public void onError(Throwable e) {
            Context context = this.context.get();
            if (context == null) return;
            if (e instanceof SocketTimeoutException) {
                Toast.makeText(context, "请求超时", Toast.LENGTH_SHORT).show();
            } else if (e instanceof ConnectException) {
                Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
                Log.d("http", "error----------->" + e.toString());
            }
            dismissProgressDialog();
        }
    
        @Override
        public void onNext(T t) {
            if (mSubscriberOnNextListener != null) {
                mSubscriberOnNextListener.onNext(t);
            }
        }
    
    }
    
    

    Http请求管理类

    public class HttpManager {
      private volatile static HttpManager singleton;
      private WeakReference<Context> context;
      private Observable observable;
      private HttpObserver observer;
    
      private HttpManager() {
    
      }
    
      public static HttpManager getInstance() {
        if (singleton == null) {
          synchronized (HttpManager.class) {
            if (singleton == null) {
              singleton = new HttpManager();
            }
          }
        }
        return singleton;
      }
    
      public HttpManager with(Context context) {
        this.context = new WeakReference<>(context);
        return singleton;
      }
    
      public HttpManager setObservable(Observable observable) {
        this.observable = observable.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .map(new ResultMap());
        return singleton;
      }
    
      //创建subscriber
      public void setDataListener(HttpDataListener listener) {
        observer = new HttpObserver(listener, context.get());
        observable.subscribe(observer);
      }
    
      //创建subscriber 自定义ProgressDialog的文字
      public void setDataListener(HttpDataListener listener, String message) {
        observable.subscribe(new HttpObserver(listener, context.get(), message));
      }
    
      //创建subscriber 自定义ProgressDialog
      public void setDataListener(HttpDataListener listener, ProgressDialog dialog) {
        observable.subscribe(new HttpObserver(listener, context.get(), dialog));
      }
    
    }
    
    

    以上,Retrofit+RxJava+OkHttp的封装就完成了。再来回顾一下Http请求的调用:

    public class MainActivity extends Activity {
    
        private TextView data;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            data = (TextView) findViewById(R.id.data);
            findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    doHttpRequest();
                }
            });
        }
    
        private void doHttpRequest() {
            HttpManager.getInstance()
                .with(this)
                .setObservable(RetrofitManager.getService().getExpress("yuantong", "200382770316"))
                .setDataListener(new HttpDataListener<List<Express>>() {
                    @Override
                    public void onNext(List<Express> list) {
                        //这里对返回数据进行处理
                        String result = "";
                        for (int i = 0; i < list.size(); i++){
                            result = result + list.get(i).toString();
                        }
                        data.setText(result);
                    }
                });
        }
    }
    

    源码下载
    https://github.com/GITbiubiubiu/RetrofitDemo

    相关文章

      网友评论

      • 24K纯帅豆:不知LZ是否有考虑到动态的baseUrl
      • youlongsam:博主,你好,请问文章中用到的HttpLoggingInterceptor,这个是从哪里来的,定义是怎样的?
        愚蠢的高小星:@youlongsam 日志拦截器,可以显示详细的请求信息
      • LJIAMING:如果我想处理请求成功,但是code不是200的数据要怎么处理:joy:
        LJIAMING:@LJIAMING 还有在onNext方法怎么能拿到那个msg和code?
        LJIAMING:@愚蠢的高小星 不是啦,就是有多个code的时候
        愚蠢的高小星:ResultMap那里把code改成你的成功码就可以了呀
      • 叫我壮士:在哪里下代码呢。博主
        愚蠢的高小星:最下面~
      • 默默_大魔王:怎么exjava1.x?
      • 简书无畏他祖先:被大神坑苦了,demo里面代码根本就没写完。里面的类的数量名字都对不上都不一样。
        简书无畏他祖先:@愚蠢的高小星 太好了,我再去看看。
        愚蠢的高小星::joy: 之前好像传错了,重新传了一遍
        5e2b2b186cfb:下了楼主的demo,调整了半天还是报错。
      • android_yiluo:调不成功,总显示类型转换异常
        android_yiluo:@愚蠢的高小星 怎么都解决不了,你的dome还不全
        愚蠢的高小星:可能是你请求的类和解析的类不一致:smile: 检查一下~
      • cwm1996: 报这个错怎麽解决?
        java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.Worker thread.
        愚蠢的高小星:可能是retrofit版本不一样
        试试把 .addConverterFactory(GsonConverterFactory.create())
        改成 .addConverterFactory(GsonConverterFactory.create(new Gson()))
      • 751fadb3ea47:请问下如果解析的json数据格式不是你这样的,要在哪里改,我们的后台并没有写成你这样,而是所有的单个元素直接对外放出
        愚蠢的高小星:ResultModel里 根据你们的json数据格式修改
      • 叶向晚77:你是怎么插入代码的,我插入的代码比较乱?
      • 亮之于东:这样的话,多个网络请求同时执行会不会有问题?
      • Caojunping:收下了 谢过博主
      • 半_农:有内存泄露的风险吧。
        愚蠢的高小星:@半_农 感谢提醒 已修复
      • d047a73d7c0e:写得很棒!持续关注,我要多多向您学习!
        愚蠢的高小星:@小小星星哇哇懂懂 :frowning:
      • Android之路:写的很不错,但是没有加入生命周期问题喔 :smiley:
        愚蠢的高小星:@Android之路 感谢支持~后续会继续完善 :smile:

      本文标题:Retrofit+RxJava+OkHttp链式封装

      本文链接:https://www.haomeiwen.com/subject/itrqpttx.html