美文网首页
你真的会 "用" RxJava & Retrofit 吗?

你真的会 "用" RxJava & Retrofit 吗?

作者: JackDaddy | 来源:发表于2020-06-06 01:00 被阅读0次
今天要来说说两个困扰了自己很久的框架:RxJava & Retrofit,本篇文章主要介绍的是如何通过这两个框架请求数据,一些常用的操作符,接下来就让我们开始吧。

1) 要使用这两个框架当然要先把这两个框架的包导进来:这里可以看到还导入了RxBinding 的包,这是为了使用防抖功能而导入的,同时因为是开发 Android,因此除了导入 RxJava 还需导入 RxAndroid,否则所需的 API 是不完整的,RxJava占所需代码的 80%,RxAndroid 占20%,只有把这两部分一起导入,才是我们完整的API,例如我们在切换线程时,最经常用到的 AndroidSchedulers.mainThread(),就是 RxAndroid包里的。

    // 依赖RxAndroid 2X 的依赖库
    // 增加RxJava 2X 的依赖库
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.0.7'

    // OkHttp相关
    implementation 'com.facebook.stetho:stetho:1.4.2'
    implementation 'com.facebook.stetho:stetho-okhttp3:1.4.2'

   // 网络请求相关
    implementation "com.squareup.retrofit2:retrofit:2.4.0"
    implementation "com.squareup.retrofit2:retrofit-mock:2.4.0"
    implementation "com.squareup.retrofit2:converter-gson:2.8.2"
    implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
    implementation "com.squareup.retrofit2:converter-scalars:2.4.0"
    implementation "com.squareup.retrofit2:adapter-rxjava2:2.4.0"
    implementation "com.squareup.retrofit2:converter-gson:2.8.2"

    implementation "com.google.code.gson:gson:2.8.2"
    implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1' // 操作功能防抖

2)使用 Retrofit 请求网络首先要写网络的请求接口,以及给这个接口打上注解(包括请求方式,地址,以及传参等)注意这里返回的是一个 Observable(被观察者)而我之前手写 Retrofit 的文章里返回的是一个 okHttp 的 Call。

public interface WanAndroid {
    //总数据
    @GET("project/tree/json")
    Observable<ProjectBean> getProject();
    //Item数据
    @GET("project/list/{pageIndex}/json")
    Observable<ProjectItem>getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);
}

3)接下来就是对 Retrofit对象 构建的封装,因为 Retrofit 是通过 okHttp 请求网络的,因此,这里其实也是对 okHttp 的封装。最后还封装了一个 RxJava 的线程切换方法,通过这个方法结合 compose 操作符就可以给上游分配到 io 异步线程,下游分配到 Android 主线程:

    //设置BaseUrl,这部发将拼接到上一步注解的前半部分
    public static String BASE_URL = "https://www.wanandroid.com/";

    public static void setBaseUrl(String baseUrl) {
        BASE_URL = baseUrl;
    }

     /**
     * 根据各种配置创建出Retrofit
     *
     * @return 返回创建好的Retrofit
     */
    public static Retrofit getOnlineCookieRetrofit() {
        // OKHttp客户端
        OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
        // 各种参数配置
        OkHttpClient okHttpClient = httpBuilder
                .addNetworkInterceptor(new StethoInterceptor())
                .readTimeout(10000, TimeUnit.SECONDS)
                .connectTimeout(10000, TimeUnit.SECONDS)
                .writeTimeout(10000, TimeUnit.SECONDS)
                .build();


        return new Retrofit.Builder().baseUrl(BASE_URL)
                // TODO 请求用 OKhttp
                .client(okHttpClient)
                // TODO 响应RxJava
                // 添加一个json解析的工具
                .addConverterFactory(GsonConverterFactory.create(new Gson()))
                // 添加rxjava处理工具
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }

    //线程切换封装
    public static <UD> ObservableTransformer<UD,UD> rxud(){
        return new ObservableTransformer<UD, UD>() {
            @Override
            public ObservableSource<UD> apply(Observable<UD> upstream) {
                           //上游分配异步线程
                return upstream.subscribeOn(Schedulers.io())
                          //下游分配主线程
                        .observeOn(AndroidSchedulers.mainThread())
                        .map(new Function<UD, UD>() {
                            @Override
                            public UD apply(UD ud) throws Exception {
                                Log.d("---", "apply: 我监听到你了,居然再执行");
                                return ud;
                            }
                        });
            }
        };
    }

4)当然还要定义返回数据的 bean 类,我这里定义了两个 ProjectBean ,ProjectItem,就是一些基本的 set & get,这里省略不写。
5)使用的时候跟使用 Retrofit 时一样,先获得 第 2) 步 定义的接口对象,通过接口对象请求网络,通过 RxJava 操作返回的数据:

    //获取全部数据
    private void getProjectData() {
        disposable = api.getProject()
                .compose(HttpUtil.rxud())//切换线程
                .subscribe(new Consumer<ProjectBean>() {
                    @Override
                    public void accept(ProjectBean projectBean) throws Exception {
                        Log.e("---", projectBean.toString());
                    }
                });
    }

可以看到这里使用了一个 Disposable 来接收操作完数据的结果,Disposable 的提供一个中断的作用,可以利用这个变量进行中断操作,当 APP 在关闭时,如果后台仍然持有Context 对象继续操作数据,这就会引发内存泄露,因此需要通过这个变量来防止内存泄漏:在onDestory 中断操作数据

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (disposable != null) {
            if (!disposable.isDisposed()) {
                disposable.dispose();
            }
        }
    }

6)当出现网络嵌套的情况,可以使用 flatMap 操作符解决,flatMap 的作用是把数据处理完之后又封装成一个被观察者继续传给下游.。同时在这里使用了防抖(指的是指定时间内允许用户操作指定次数某控件):

    //使用防抖+网络嵌套问题
    //这里第一次层级尝试使用map操作符,但是效果不佳,查看map/flatMap源码:
    //public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)
    //public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)
    //可以看到flatMap操作符的Function的第二个入参(下游)是个被观察者,将这个被观察者作为下一步操作的上游
    //而map的第二个入参是没有限制的泛型,
    //总结:fltaMap 与 map 的区别是fltaMap 让用户操作完成之后又封装成一个被观察者继续向下传递
    private void getDataByView() {
        Button btnNet = findViewById(R.id.btn_net);
        disposable = RxView.clicks(btnNet)
                .throttleFirst(2, TimeUnit.SECONDS)//2s-允许点击一次
                .observeOn(Schedulers.io())
                .flatMap(
                        new Function<Object, ObservableSource<ProjectBean>>() {
                            @Override
                            public ObservableSource<ProjectBean> apply(Object o) throws Exception {
                                return api.getProject();
                            }
                        })
                .flatMap(
                        new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
                            @Override
                            public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
                                return Observable.fromIterable(projectBean.getData());
                            }
                        })
                .flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
                    @Override
                    public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
                        return api.getProjectItem(1, dataBean.getId());
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<ProjectItem>() {
                    @Override
                    public void accept(ProjectItem projectItem) throws Exception {

                    }
                });
    }

7)map操作符:作用是将上游的数据传再到下游观察者之前进行一次操作,转换成用户所需要的类型后再传给观察者,因此观察者接收到的上游就是被 map 转换之后的下游:

     //获取全部数据
    private void getProjectMap() {
        disposable = api.getProject()
                .compose(HttpUtil.rxud())//切换线程
                //注意这里上游是 ProjectBean,提供给下游观察者的是 String
                .map(new Function<ProjectBean, String>() {
                    @Override //这里返回的 String 提供给下游观察者
                    public String apply(ProjectBean projectBean) throws Exception {
                        return null;
                    }
                })
                 //观察者接收到 map 返回的 String
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String str) throws Exception {
                        Log.e("---", str);
                    }
                });
    }

8)**doOnNext操作符:在观察者的 next 操作之前先执行这个方法,一般用在一连续的操作(比如注册后显示UI,紧接着跳转登录)map 是在上游传给下游时进行一次拦截,而 doOnNext 则是在下游往上游回传时进行拦截:

     //doOnNext练习
    //doOnNext:就是在拿到结果交给订阅者之前截断,处理完成后再交给订阅者的Next操作
    //map操作是在数据发送数据时,上游与下游之间截断
    //doOnNext 是在拿到数据后,下游往上游回传时截断
    private void getDataByNext(){
        disposable = api.getProject()
                .compose(HttpUtil.rxud())
                .doOnNext(new Consumer<ProjectBean>() {
                    @Override
                    public void accept(ProjectBean projectBean) throws Exception {
                        Log.e("---","先执行这里");
                    }
                })
                .subscribe(new Consumer<ProjectBean>() {
                    @Override
                    public void accept(ProjectBean projectBean) throws Exception {
                        Log.e("---","后执行这里");
                    }
                });
    }

本篇主要以使用为主,RxJava 的原理性将在下篇文章讲解,希望对你有所帮助~

相关文章

网友评论

      本文标题:你真的会 "用" RxJava & Retrofit 吗?

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