一、前言

二、BaseResponse与BaseObserver的封装

三、RxHelper调度类封装

四、Retrofit初始化封装

五、细节完善

1、服务错误信息处理

2、添加“正在加载”弹窗

3、Retorfit请求方法汇总

4、提交参数方式汇总(可忽略)

六、总结

七、Demo地址

八、内容推荐


一、前言

由于《Rxjava+Retrofit网络请求框架封装(一)》篇幅太长、防止朋友们看的太累,产生视觉疲劳。所以把基础部分和封装部分-分开写。这篇主要是实现如何更简单的去实现网络请求,提高项目后期优化和维护效率。当然有更多的好处,自己细细体会。

作者不善言语,只做粗略描述,见谅!见谅!

二、BaseResponse与BaseObserver的封装

BaseResponse是个人自定义命名的一个类,主要用来对返回数据进行抽象。

BaseObserver是对返回数据的基础数据部分进行统一处理。

为什么要对返回数据进行抽象呢?

大部分公司后台接口返回数据都遵循一定的规范:个人粗略理解分为:基础数据与需求数据

基于上一篇的基础介绍,我们可以获取到后台请求数据如下。


    
简单理解就是基础数据部分key值不会改变 

而需求数据部分也就是Demo里面的数据会根据不同的需求而改变

BaseResponse就是对基础数据进行封装处理。

实现步骤:

1、根据基础数据定义BaseResponse

2、修改API接口返回数据类型

3、对基础数据统一处理

1、根据基础数据定义BaseResponse

public class BaseResponse {    private int res_code;    private String err_msg;    private T demo;    public int getRes_code() {        return res_code;    }    public void setRes_code(int res_code) {        this.res_code = res_code;    }    public String getErr_msg() {        return err_msg;    }    public void setErr_msg(String err_msg) {        this.err_msg = err_msg;    }    public T getDemo() {        return demo;    }    public void setDemo(T demo) {        this.demo = demo;    }}

当然我们需求数据也需重新定义

public class Demo {    @Override    public String toString() {        return "Demo{" + "id='" + id + '\'' +                ", appid='" + appid + '\'' +                ", name='" + name + '\'' +                ", showtype='" + showtype + '\'' +                '}';    }    private String id;    private String appid;    private String name;    private String showtype;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getAppid() {        return appid;    }    public void setAppid(String appid) {        this.appid = appid;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getShowtype() {        return showtype;    }    public void setShowtype(String showtype) {        this.showtype = showtype;    }}

2、修改API接口返回数据类型

   // @GET(Constans.retrofit)   // Observable getRetrofit1();   // 把原先的Bean类分成BaseResponse基础数据与Demo需求数据两个类    @GET(Constans.retrofit)    Observable> getRetrofit2();

3、对基础数据统一处理

/** * 创建Base抽象类实现Observer */public abstract class BaseObserver implements Observer> {    private static final String TAG = "BaseObserver";    @Override    public void onSubscribe(Disposable d) {        Log.e(TAG, "onSubscribe: " );    }    @Override    public void onNext(BaseResponse response) {        //在这边对 基础数据 进行统一处理  举个例子:        if(response.getRes_code()==200){            onSuccess(response.getDemo());        }else{            onFailure(null,response.getErr_msg());        }    }    @Override    public void onError(Throwable e) {        Log.e(TAG, "Throwable: " + e.getMessage());    }    @Override    public void onComplete() {        Log.e(TAG, "onComplete: " );    }    public abstract void onSuccess(T demo);    public abstract void onFailure(Throwable e,String errorMsg);}

请求网络数据

 retrofit.create(ApiUrl.class)                .getRetrofit2()                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                //绑定生命周期                .compose(bindUntilEvent(ActivityEvent.DESTROY))                .subscribe(new BaseObserver(){                    @Override                    public void onSuccess(Demo demo) {                        Log.e(TAG, "onSuccess: "+demo);                    }                    @Override                    public void onFailure(Throwable e, String errorMsg) {                        Log.e(TAG, "onFailure: "+errorMsg);                    }                });//打印结果: onSuccess: Demo{id='1001', appid='1021', name='sss', showtype='text'}

对返回数据的处理写到这里就结束了、不知道朋友看懂没。

看不懂?  没关系,敲代码实现一下好理解

还是看不懂? 那就多敲几遍。。。。再看不懂  去把作者拉出来溜溜

三、RxHelper调度类封装

忘了从哪里抄来的,这里简单介绍一下。

RxHelper主要是对执行线程和绑定生命周期几个方法进行封装,

大致实现如下:

app builde配置

android {    .......    compileOptions {        targetCompatibility 1.8        sourceCompatibility 1.8    }}
/** * 调度类 */public class RxHelper {    public static  ObservableTransformer observableIO2Main(final Context context) {        return upstream -> {            Observable observable = upstream.subscribeOn(Schedulers.io())                    .observeOn(AndroidSchedulers.mainThread());            return composeContext(context, observable);        };    }    public static  ObservableTransformer observableIO2Main(final RxFragment fragment) {        return upstream -> upstream.subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread()).compose(fragment.bindToLifecycle());    }    public static  FlowableTransformer flowableIO2Main() {        return upstream -> upstream                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread());    }    private static  ObservableSource composeContext(Context context, Observable observable) {        if(context instanceof RxActivity) {            return observable.compose(((RxActivity) context).bindUntilEvent(ActivityEvent.DESTROY));        } else if(context instanceof RxFragmentActivity){            return observable.compose(((RxFragmentActivity) context).bindUntilEvent(ActivityEvent.DESTROY));        }else if(context instanceof RxAppCompatActivity){            return observable.compose(((RxAppCompatActivity) context).bindUntilEvent(ActivityEvent.DESTROY));        }else {            return observable;        }    }}

使用方式:

compose(RxHelper.observableIO2Main(this))

四、Retrofit初始化封装

这部分才是重点应该写在最前面,被我遗漏。尴尬---

之前的调用方式:

我们不可能每次要请求网络就重复去创建初始化Retrofit。所以我们需要对Retrofit进行单例封装。

import android.support.annotation.NonNull;import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;import retrofit2.Retrofit;import retrofit2.converter.gson.GsonConverterFactory;/** * Retrofit封装 */public class RetrofitUtils {    private static final String TAG = "RetrofitUtils";    private static ApiUrl mApiUrl;    /**     * 单例模式     */    public static ApiUrl getApiUrl() {        if (mApiUrl == null) {            synchronized (RetrofitUtils.class) {                if (mApiUrl == null) {                    mApiUrl = new RetrofitUtils().getRetrofit();                }            }        }        return mApiUrl;    }    private RetrofitUtils(){}    public ApiUrl getRetrofit() {        // 初始化Retrofit        ApiUrl apiUrl = initRetrofit(initOkHttp()) .create(ApiUrl.class);        return apiUrl;    }    /**     * 初始化Retrofit     */    @NonNull    private Retrofit initRetrofit(OkHttpClient client) {        return new Retrofit.Builder()                    .client(client)                    .baseUrl(Constans.BaseUrl)                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())                    .addConverterFactory(GsonConverterFactory.create())                    .build();    }    /**     * 初始化okhttp     */    @NonNull    private OkHttpClient initOkHttp() {        return new OkHttpClient().newBuilder()                    .readTimeout(Constans.DEFAULT_TIME, TimeUnit.SECONDS)//设置读取超时时间                    .connectTimeout(Constans.DEFAULT_TIME, TimeUnit.SECONDS)//设置请求超时时间                    .writeTimeout(Constans.DEFAULT_TIME,TimeUnit.SECONDS)//设置写入超时时间                    .addInterceptor(new LogInterceptor())//添加打印拦截器                    .retryOnConnectionFailure(true)//设置出现错误进行重新连接。                    .build();    }}

若未看懂单例请参考《JAVA 设计模式——单例模式》

使用方式: 

ApiUrl类

调用:

RetrofitUtils.getApiUrl().getDemo()                .compose(RxHelper.observableIO2Main(this))                .subscribe(new BaseOberver(){                    @Override                    public void onSuccess(Demo demo) {                        Log.e(TAG, "onSuccess: "+demo);                    }                    @Override                    public void onFailure(Throwable e, String errorMsg) {                        Log.e(TAG, "onFailure: "+errorMsg);                    }                });

执行顺序分别是:初始化Retrofit——>调用请求接口——>调用执行线程——>输出结果

到这里差不多了,我已经封装不下去了。。。   能力有限止步于此T-T 请朋友们手下留情

五、细节完善

1、服务错误信息处理

BaseObserver 对请求成功数进行了统一处理 ,但并未对服务器返回错误进行处理。

这里从某个大神Copy了个工具类RxExceptionUtils来对错误信息进行处理。

具体代码如下:

import org.json.JSONException;import java.net.SocketTimeoutException;import java.net.UnknownHostException;import java.text.ParseException;import retrofit2.HttpException;/** * 异常处理 */public class RxExceptionUtil {    public static String exceptionHandler(Throwable e){        String errorMsg = "未知错误";        if (e instanceof UnknownHostException) {            errorMsg = "网络不可用";        } else if (e instanceof SocketTimeoutException) {            errorMsg = "请求网络超时";        } else if (e instanceof HttpException) {            HttpException httpException = (HttpException) e;            errorMsg = convertStatusCode(httpException);        } else if (e instanceof ParseException || e instanceof JSONException                || e instanceof JSONException) {            errorMsg = "数据解析错误";        }        return errorMsg;    }    private static String convertStatusCode(HttpException httpException) {        String msg;        if (httpException.code() >= 500 && httpException.code() < 600) {            msg = "服务器处理请求出错";        } else if (httpException.code() >= 400 && httpException.code() < 500) {            msg = "服务器无法处理请求";        } else if (httpException.code() >= 300 && httpException.code() < 400) {            msg = "请求被重定向到其他页面";        } else {            msg = httpException.message();        }        return msg;    }}

请在BaseObserver类里面的onError方法里面调用

     @Override    public void onError(Throwable e) {//服务器错误信息处理        onFailure(e, RxExceptionUtil.exceptionHandler(e));    }

2、添加“正在加载”弹窗

import android.app.ProgressDialog;import android.content.Context;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.widget.Toast;import io.reactivex.disposables.Disposable;/** * Observer加入加载框 * @param  */public abstract class MyObserver extends BaseObserver {    private boolean mShowDialog;    private ProgressDialog dialog;    private Context mContext;    private Disposable d;    public MyObserver(Context context, Boolean showDialog) {        mContext = context;        mShowDialog = showDialog;    }    public MyObserver(Context context) {        this(context,true);    }    @Override    public void onSubscribe(Disposable d) {        this.d = d;        if (!isConnected(mContext)) {            Toast.makeText(mContext,"未连接网络",Toast.LENGTH_SHORT).show();            if (d.isDisposed()) {                d.dispose();            }        } else {            if (dialog == null && mShowDialog == true) {                dialog = new ProgressDialog(mContext);                dialog.setMessage("正在加载中");                dialog.show();            }        }    }    @Override    public void onError(Throwable e) {        if (d.isDisposed()) {            d.dispose();        }        hidDialog();        super.onError(e);    }    @Override    public void onComplete() {        if (d.isDisposed()) {            d.dispose();        }        hidDialog();        super.onComplete();    }    public void hidDialog() {        if (dialog != null && mShowDialog == true)            dialog.dismiss();        dialog = null;    }    /**     * 是否有网络连接,不管是wifi还是数据流量     * @param context     * @return     */    public static boolean isConnected(Context context)    {        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);        NetworkInfo info = cm.getActiveNetworkInfo();        if (info == null)        {            return false;        }        boolean available = info.isAvailable();        return available;    }    /**     * 取消订阅     */    public void cancleRequest(){        if (d!=null&&d.isDisposed()) {            d.dispose();            hidDialog();        }    }}

使用方式:

3、Retorfit请求方法汇总

ApiUrl类

import io.reactivex.Observable;import okhttp3.MultipartBody;import okhttp3.RequestBody;import okhttp3.ResponseBody;import retrofit2.Call;import retrofit2.http.Body;import retrofit2.http.DELETE;import retrofit2.http.Field;import retrofit2.http.FieldMap;import retrofit2.http.FormUrlEncoded;import retrofit2.http.GET;import retrofit2.http.Header;import retrofit2.http.HeaderMap;import retrofit2.http.Headers;import retrofit2.http.Multipart;import retrofit2.http.POST;import retrofit2.http.PUT;import retrofit2.http.Part;import retrofit2.http.PartMap;import retrofit2.http.Path;import retrofit2.http.Query;import retrofit2.http.QueryMap;import retrofit2.http.Streaming;import retrofit2.http.Url;public interface ApiUrl {    @GET(Constans.retrofit)    Call getRetrofit();    @GET(Constans.retrofit)    Observable> getDemo();    /**     * TODO Get请求     */    //第一种方式:GET不带参数    @GET("retrofit.txt")    Observable> getUser();    @GET    Observable getUser(@Url String url);     @GET    Observable getUser1(@Url String url); //简洁方式   直接获取所需数据    //第二种方式:GET带参数    @GET("api/data/{type}/{count}/{page}")    Observable getUser(@Path("type") String type, @Path("count") int count, @Path("page") int page);    //第三种方式:GET带请求参数:https://api.github.com/users/whatever?client_id=xxxx&client_secret=yyyy    @GET("users/whatever")    Observable getUser(@Query("client_id") String id, @Query("client_secret") String secret);    @GET("users/whatever")    Observable getUser(@QueryMap Map info);    /**     * TODO POST请求     */    //第一种方式:@Body    @Headers("Accept:application/json")    @POST("login")    Observable postUser(@Body RequestBody body);    //第二种方式:@Field    @Headers("Accept:application/json")    @POST("auth/login")    @FormUrlEncoded    Observable postUser(@Field("username") String username, @Field("password") String password);    //多个参数    Observable postUser(@FieldMap Map map);        /**     * TODO DELETE     */    @DELETE("member_follow_member/{id}")    Observable delete(@Header("Authorization") String auth, @Path("id") int id);        /**     * TODO PUT     */    @PUT("member")    Observable put(@HeaderMap Map headers,                                   @Query("nickname") String nickname);        /**     * TODO 文件上传     */    @Multipart    @POST("upload")    Observable upload(@Part("description") RequestBody description, @Part MultipartBody.Part file);    //亲测可用    @Multipart    @POST("member/avatar")    Observable uploadImage(@HeaderMap Map headers, @Part MultipartBody.Part file);        /**     * 多文件上传     */    @Multipart    @POST("register")    Observable upload(@PartMap Map params, @Part("description") RequestBody description);    //Observable upload(@Part() List parts);        @Multipart    @POST("member/avatar")    Observable uploadImage1(@HeaderMap Map headers, @Part List file);        /**     * 来自https://blog.csdn.net/impure/article/details/79658098     * @Streaming 这个注解必须添加,否则文件全部写入内存,文件过大会造成内存溢出     */    @Streaming    @GET    Observable download(@Header("RANGE") String start, @Url String url);}

4、提交参数方式汇总(可忽略)

/** * 提交参数方式 */public class RequestUtils {    /**     * Get 请求demo     * @param context     * @param observer     */    public static void getDemo(RxAppCompatActivity context, MyObserver observer){        RetrofitUtils.getApiUrl()                .getDemo().compose(RxHelper.observableIO2Main(context))                .subscribe(observer);    }    /**     * Post 请求demo     * @param context     * @param consumer     */    public static void postDemo(RxAppCompatActivity context, String name, String password, Observer consumer){        RetrofitUtils.getApiUrl()                .postUser(name,password).compose(RxHelper.observableIO2Main(context))                .subscribe(consumer);    }    /**     * Put 请求demo     * @param context     * @param consumer     */    public static void putDemo(RxFragment context, String access_token,Observer consumer){        Map headers = new HashMap();        headers.put("Accept","application/json");        headers.put("Authorization",access_token);        RetrofitUtils.getApiUrl()                .put(headers,"厦门").compose(RxHelper.observableIO2Main(context))                .subscribe(consumer);    }    /**     * Delete 请求demo     * @param context     * @param consumer     */    public static void deleteDemo(RxFragment context, String access_token,Observer consumer){        RetrofitUtils.getApiUrl()                .delete(access_token,1).compose(RxHelper.observableIO2Main(context))                .subscribe(consumer);    }    /**     * 上传图片     * @param context     * @param observer     */    public static void upImagView(RxFragment context, String  access_token,String str, Observer  observer){        File file = new File(str);//        File file = new File(imgPath);        Map header = new HashMap();        header.put("Accept","application/json");        header.put("Authorization",access_token);//        File file =new File(filePath);        RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);//        RequestBody requestFile =//                RequestBody.create(MediaType.parse("multipart/form-data"), file);        MultipartBody.Part body =                MultipartBody.Part.createFormData("file", file.getName(), reqFile);        RetrofitUtils.getApiUrl().uploadImage(header,body).compose(RxHelper.observableIO2Main(context))                .subscribe(observer);    }    /**     * 上传多张图片     * @param files     */    public static void upLoadImg(RxFragment context,String access_token,List files, Observer  observer1){        Map header = new HashMap();        header.put("Accept","application/json");        header.put("Authorization",access_token);        MultipartBody.Builder builder = new MultipartBody.Builder()                .setType(MultipartBody.FORM);//表单类型        for (int i = 0; i < files.size(); i++) {            File file = files.get(i);            RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/*"), file);            builder.addFormDataPart("file", file.getName(), photoRequestBody);        }        List parts = builder.build().parts();        RetrofitUtils.getApiUrl().uploadImage1(header,parts).compose(RxHelper.observableIO2Main(context))                .subscribe(observer1);    }}

六、总结

如若加上RequestUtils则代码中请求网络方式如下:

        RequestUtils.getDemo(this, new MyObserver(this) {            @Override            public void onSuccess(Demo result) {                tv_retrofit.setText(result.toString());            }            @Override            public void onFailure(Throwable e, String errorMsg) {                tv_retrofit.setText(errorMsg);            }        });

若后台返回的Demo不是个对象 而是数组咋办  不用慌 

其他相关的地方也要加上  List<>

 RequestUtils.getDemoList(this, new MyObserver>(this) {            @Override            public void onSuccess(List result) {                for (Demo demo:result){                    Log.e(TAG, "onSuccess: "+demo.toString() );                }                tv_retrofit.setText(result.toString());            }            @Override            public void onFailure(Throwable e, String errorMsg) {                tv_retrofit.setText(errorMsg);            }        });

输出如下:

附上Url链接:

public final static  String BaseUrl = "http://120.78.186.81/api/";public final static  String retrofit = "values/5";public final static  String retrofitList = "values";

最后目录如下:

七、Demo地址

https://github.com/DayorNight/RxjavaRetrofit2

八、内容推荐

简书:《Android Rxjava+Retrofit网络请求框架封装(二)》

《Android Rxjava+Retrofit网络请求框架封装(一)》

《Android 仿微信全局字体大小调整》

《Android JUnit单元测试》

《Android Log日志封装》

如果你觉得我写的不错或者对您有所帮助的话

不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈

看在我花了这么多时间整理写成文章分享给大家的份上,记得手下留情哈

您的每个举动都是对我莫大的支持

更多相关文章

  1. Android(安卓)网络学习
  2. Android中ContentProvider和ContentResolver使用入门
  3. android屏幕刷新显示机制
  4. Android的四大组件的作用
  5. 通过广播获取Android屏幕旋转事件
  6. Android(安卓)Bluetooth蓝牙技术基础讲解
  7. 自学Android(安卓)----- Activity的生命周期
  8. 2018-04-08 2018年Android(安卓)面试题
  9. Android读书笔记---View基础

随机推荐

  1. DateUtils时间工具类
  2. Android(安卓)get layout height and wid
  3. Android(安卓)SQLite数据库学习笔记
  4. No 93 · android xml的生成和解析
  5. JAVA按钮显示用户名+密码
  6. android笔记4-xml解析
  7. Android(安卓)Studio Button按钮点击事件
  8. android 中的编译选项的对应关系
  9. Android打包常见问题的解决办法
  10. 边框的两种写法