美文网首页RxJava框架【库】Android开发
RxJava<第三十二篇>:RxJava+Retro

RxJava<第三十二篇>:RxJava+Retro

作者: NoBugException | 来源:发表于2019-04-14 20:19 被阅读16次

    本章主要针对RxJavaRetrofitOkHttp结合使用,现在说明一下三者的职责所在。

    OkHttp:负责网络请求;
    Retrofit:主要负责网络请求接口的封装,结合OkHttp可以处理网络请求的结果;
    RxJava:负责网络请求的异步;

    (1)权限

    网络请求别忘了添加网络权限

    <uses-permission android:name="android.permission.INTERNET" />
    
    (2)依赖
    • RxJava依赖
    implementation 'io.reactivex.rxjava2:rxjava:2.1.3'
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
    

    或者

    implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2'
    

    如果使用rxbinding,就添加rxbinding相关依赖,rxbinding依赖本身支持rxjava和rxandroid,所以如果添加rxbinding依赖就可以去除rxjava和rxandroid依赖了。

    • okhttp3依赖
    implementation 'com.squareup.okhttp3:okhttp:3.14.0'
    
    • retrofit依赖
    implementation 'com.squareup.retrofit2:retrofit:2.5.0'
    
    • 其它辅助依赖
    //gson依赖
    implementation 'com.google.code.gson:gson:2.8.5'
    //gson转换器依赖
    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
     //日志拦截器依赖
    implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
    
    (3)具体实现
        public interface SearchFileAPIService {
       
                @FormUrlEncoded
                @POST("/selfClaim/interface/carList")
                Observable<ArrayList<Car>> getCarList(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
        
        }
    
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://xxxx:7001")
                .addConverterFactory(GsonConverterFactory.create(new Gson()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        SearchFileAPIService retrofitTest = retrofit.create(SearchFileAPIService.class);
        Observable<ArrayList<Car>> observable = retrofitTest.getCarList("868256021322879", "862679", "c907d5df8b26550eaf2841ed9bcf51bb44b9ae1b", "d3974829a20747579c90e2004a5ed1c5");
        observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<ArrayList<Car>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        //开始请求
                    }
    
                    @Override
                    public void onNext(ArrayList<Car> cars) {
                        //成功
                        for(Car car : cars){
                            Log.d("aaa", car.getCarNumber());
                        }
                    }
    
                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        //失败
                        Log.d("aaa", "onFailure:"+e.getCause() + "\n" + e.getMessage());
                    }
    
                    @Override
                    public void onComplete() {
                        //结束请求
                    }
                });
    

    单独使用Retrofit,网络请求的返回值类型是Call,与RxJava结合使用后返回值变成了observable,这样做的好处是:

    • 可以方便的控制线程
    • 可以知道网络请求什么时候开始以及什么时候结束

    另外,OkHttp可以设置网络超时以及其他配置。

    (4)学会自主封装网络请求

    封装网络请求需要大家自主完成,因为不同的项目可能有不同的封装方式,思路如下:

    • onSubscribe代码网络请求的开始,可以弹出网络请求进度条,onComplete 代表网络请求的结束,可以关闭网络请求进度条;
    • onError可以处理一些网络异常,可用于统一处理;
    • onNext用于处理接口返回的数据;
    • 一般项目中会存在多个接口,那么我们不可能在将(3) 中的一大段代码在项目中多次出现,这样造成代码的冗余;

    下面我直接贴一下我自己封装之后的代码,用到的技术有RxJavaRetrofitOkHttpMVPrxjava

    (1) RetrofitAPI.java

    • Retrofit接口集中定义
    public interface RetrofitAPI {
    
        @FormUrlEncoded
        @POST("/selfClaim/interface/carList")
        Observable<ArrayList<Car>> getCarList(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
    
        @FormUrlEncoded
        @POST("/selfClaim/interface/interface1")
        Observable<ArrayList<Car>> getA(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
    
        @FormUrlEncoded
        @POST("/selfClaim/interface/interface2")
        Observable<ArrayList<Car>> getB(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
    
    }
    

    (2) RetrofitUtils.java

    • 封装了一些Retrofit语句,可以防止代码的冗余;
    • 使用单例设计模式防止RetrofitUtils对象内存泄漏;
    • 创建日志拦截器,可以拦截报文日志;
    • 定义通用方法getDataFromAPI,泛型T使接口封装更加通用,结合GsonConverterFactory一起使用;
    • 使用AutoDispose,使自动取消订阅,防止内存泄漏;
    • 使用observable.subscribeOn(Schedulers.io()),让网络请求在异步线程执行;
    • 使用observeOn(AndroidSchedulers.mainThread())让更新界面的操作在UI线程上执行;
    • 添加网络请求进度条对话框;
    • onError方法里集中处理网络异常情况;
    public class RetrofitUtils {
    
        private RetrofitAPI retrofitAPI;
    
        private String BASE_URL = "http://xxx.124.175.239:7001";
    
        private RetrofitUtils(){
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(10, TimeUnit.SECONDS)//设置连接超时时长
                    .readTimeout(20, TimeUnit.SECONDS)//设置读超时时长
                    .writeTimeout(20, TimeUnit.SECONDS)//设置写超时时长
                    .addInterceptor(getHttpLoggingInterceptor())//添加日志拦截器
                    .build();
            Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(new Gson()))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(client)
                    .build();
            retrofitAPI = retrofit.create(RetrofitAPI.class);
        }
    
        static class SingleHolder{
            public static RetrofitUtils instance = new RetrofitUtils();
        }
    
        public static RetrofitUtils getInstance(){
            return RetrofitUtils.SingleHolder.instance;
        }
    
        /**
         * 创建日志拦截器
         * @return
         */
        private HttpLoggingInterceptor getHttpLoggingInterceptor() {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
                    new HttpLoggingInterceptor.Logger() {
    
                        @Override
                        public void log(String message) {
                            Log.e("aaa", "log = " + message);
                        }
    
                    });
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            return loggingInterceptor;
        }
    
        public RetrofitAPI getRetrofitAPI(){
            return retrofitAPI;
        }
    
    
        /**
         * 通用方法
         * @param activity
         * @param observable
         * @param <T>
         */
        public <T> void getDataFromAPI(Activity activity, Observable<T> observable, ResultCallBack callBack){
            observable.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    //AutoDispose的关键语句
                    .as(AutoDispose.<T>autoDisposable(AndroidLifecycleScopeProvider.from((LifecycleOwner) activity)))
                    .subscribe(new Observer<T>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            //开始请求
                            if(activity instanceof BaseActivity){
                                BaseActivity baseActivity = (BaseActivity) activity;
                                baseActivity.loadingDialogShow("请稍等...");
                            }
                        }
    
                        @Override
                        public void onNext(T t) {
                            //成功
                            callBack.success(t);
    
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            e.printStackTrace();
                            //失败
                            Log.d("aaa", "onFailure:"+e.getCause() + "\n" + e.getMessage());
    
                            if (e instanceof SocketTimeoutException) {
                                callBack.failed("网络中断,请检查您的网络状态!");
                            } else if (e instanceof ConnectException) {
                                callBack.failed("网络中断,请检查您的网络状态!");
                            }else{
                                callBack.failed("未知异常!");
                            }
    
                            if(activity instanceof BaseActivity){
                                BaseActivity baseActivity = (BaseActivity) activity;
                                baseActivity.loadingDialogDismiss();
                            }
                        }
    
                        @Override
                        public void onComplete() {
                            //结束请求
                            if(activity instanceof BaseActivity){
                                BaseActivity baseActivity = (BaseActivity) activity;
                                baseActivity.loadingDialogDismiss();
                            }
                        }
                    });
        }
    
    }
    

    (3) 网络请求进度条对话框

    <!-- 自定义loading dialog -->
    <style name="loading_dialog" parent="android:style/Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
        <item name="android:windowBackground">@color/bg_dialog_white</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>
    
    public class BaseActivity extends AppCompatActivity {
    
        private Dialog loadingDialog;
    
        /**
         * 弹出进度条
         */
        public void loadingDialogShow(String msg) {
            TextView tipTextView = null;
            if (loadingDialog == null) {
                LayoutInflater inflater = LayoutInflater.from(this);
                View v = inflater.inflate(R.layout.loading_dialog, null);// 得到加载view
                LinearLayout layout = v.findViewById(R.id.dialog_view);// 加载布局
                ImageView spaceshipImage = v.findViewById(R.id.img);
                tipTextView = v.findViewById(R.id.tipTextView);// 提示文字
                // 加载动画
                Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.loading_animation);
                // 使用ImageView显示动画
                spaceshipImage.startAnimation(hyperspaceJumpAnimation);
                tipTextView.setText(msg);// 设置加载信息
    
                loadingDialog = new Dialog(this, R.style.loading_dialog);// 创建自定义样式dialog
                loadingDialog.setCanceledOnTouchOutside(false);
                loadingDialog.setCancelable(true);// 不可以用“返回键”取消
                loadingDialog.setContentView(layout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));// 设置布局
            }
    
            tipTextView.setText(msg);
    
            if (!loadingDialog.isShowing()) {
                loadingDialog.show();
            }
        }
    
        /**
         * 关闭进度条
         */
        public void loadingDialogDismiss() {
    
            if (loadingDialog != null && loadingDialog.isShowing()) {
                try {
                    loadingDialog.dismiss();
                    loadingDialog = null;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //关闭进度条
            loadingDialogDismiss();
        }
    }
    

    loading_dialog.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/dialog_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="10dp" >
    
        <ImageView
            android:id="@+id/img"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:scaleType="center"
            android:src="@mipmap/aliwx_img_loading" />
    
        <TextView
            android:id="@+id/tipTextView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:layout_marginLeft="5dp"
            android:textColor="#FF34A350"
            android:text="数据加载中……"
            android:textSize="16sp" />
    
    </LinearLayout>
    

    图标:aliwx_img_loading.png

    aliwx_img_loading.png

    (4) HttpModel.java

    • MVP模式的Model
    public class HttpModel {
    
        private String IMEI = "868256021322879";
        private String appid = "862679";
        private String appkey = "c907d5df8b26550eaf2841ed9bcf51bb44b9ae1b";
        private RetrofitAPI retrofitAPI;
    
    
        public HttpModel(){
            retrofitAPI = RetrofitUtils.getInstance().getRetrofitAPI();
        }
    
        /**
         * 获取车辆列表
         */
        public void getCarList(Activity activity, String userID, ResultCallBack callBack){
            RetrofitUtils.getInstance().getDataFromAPI(activity, retrofitAPI.getCarList(IMEI, appid, appkey, userID), callBack);
        }
    
        /**
         * 获取车辆列表
         */
        public void getA(Activity activity, String userID, ResultCallBack callBack){
            RetrofitUtils.getInstance().getDataFromAPI(activity, retrofitAPI.getA(IMEI, appid, appkey, userID), callBack);
        }
    
        /**
         * 获取车辆列表
         */
        public void getB(Activity activity, String userID, ResultCallBack callBack){
            RetrofitUtils.getInstance().getDataFromAPI(activity, retrofitAPI.getB(IMEI, appid, appkey, userID), callBack);
        }
    }
    

    (5) IMainView.java

    • MVP模式的view
    public interface IMainView {
    
        void setResult(String result);
    
    }
    

    (6) 辅助接口

    public interface ResultCallBack<T> {
    
        void success(T t);
    
        void failed(String error);
    
    }
    

    (7) MainPresenter.java

    • MVP模式的Presenter
    public class MainPresenter {
    
        private HttpModel httpModel;
        private IMainView view;
    
        public MainPresenter(IMainView view){
            httpModel = new HttpModel();
            this.view = view;
        }
    
        /**
         * 获取车辆列表1
         * @param activity
         */
        public void getCarList(Activity activity, String userID){
            httpModel.getCarList(activity, userID, new ResultCallBack<ArrayList<Car>>() {
                @Override
                public void success(ArrayList<Car> cars) {
                    if(cars != null && cars.size() > 0){
                        view.setResult("已获取到车辆!");
                        for(int i=0;i<cars.size();i++){
                            Log.d("aaa", "success:"+cars.get(i).getCarNumber());
                        }
                    }else{
                        view.setResult("没有获取到车辆!");
                    }
    
                }
    
                @Override
                public void failed(String error) {
                    view.setResult(error);
                }
            });
        }
    
    }
    

    (8) 界面

    • 界面上的按钮使用RxBing解决抖动问题(防暴力点击);
    • 在关闭页面的时候将mainPresenter置空,防止内存泄漏
    public class MainActivity extends BaseActivity implements IMainView {
    
        private TextView result_text;
        private MainPresenter mainPresenter;
    
        @SuppressLint("CheckResult")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            result_text = findViewById(R.id.result_text);
    
            mainPresenter = new MainPresenter(this);
    
            RxView.clicks(findViewById(R.id.bt_1))
                    .throttleFirst(2, TimeUnit.SECONDS)
                    //AutoDispose的关键语句
                    .as(AutoDispose.<Unit>autoDisposable(AndroidLifecycleScopeProvider.from(this)))
                    .subscribe(new Consumer<Unit>() {
                        @Override
                        public void accept(Unit unit) throws Exception {
                            //获取车辆别表
                            mainPresenter.getCarList(MainActivity.this, "d3974829a20747579c90e2004a5ed1c5");
    
                        }
                    });
        }
    
        @Override
        public void setResult(String result) {
            //显示结果
            result_text.setText(result);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mainPresenter = null;
        }
    }
    
    (5)展示效果
    44.gif

    相关文章

      网友评论

        本文标题:RxJava<第三十二篇>:RxJava+Retro

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