继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

开始使用Retrofit2+RXjava+Gson

汪汪一只猫
关注TA
已关注
手记 575
粉丝 129
获赞 718

配置依赖

dependencies{    //添加retrofit2 的依赖 添加这个依赖就默认添加了okhttp依赖
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    //支持Gson 及 rxjava
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
    //okhttp log 工具
    compile 'com.squareup.okhttp3:logging-interceptor:3.1.2'
    //gson
    compile 'com.google.code.gson:gson:2.5'
    //rxjava
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'io.reactivex:rxjava:1.1.3'}

开始使用

Retrofit2快速入门

官网示例

如果使用Gson及Rxjava的话 生成Retrofit需要这样

new Retrofit.Builder()                .baseUrl("your base url")                .addConverterFactory(GsonConvertFactory.create())                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .client(client)                .build();

然后对应Api接口的样子类似下面这样:

    @GET("user/token")
    Observable<JSONObject> fetchToken();    @Headers("Cache-Control: public,max-age=30")    @POST("user/login")
    Observable<User> login(@Body LoginRequest loginRequest);    @FormUrlEncoded
    @POST("user/user-feed-back")
    Observable<JSONObject> feedback(@Field("content") String content);

这些是比较常用的三种方式

实现自定义的设置

通过上边的配置已经可以使用了,但是我们还会有一些常用需求需要加在里面,比如请求失败的统一处理等。

添加日志

添加日志是在OkHttp中使用日志拦截器

OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));

重写请求头

这个操作也是对OkHttp中使用拦截器(比如每次请求需要携带的请求头和强制缓存)

builder.addNetworkInterceptor(new RewriteInterceptor())


final static class RewriteInterceptor implements Interceptor {
        @Override        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request originalRequest = chain.request();
            Request reWriteRequest = originalRequest.newBuilder()//添加默认的头
                                                    .header("Os", "android")
                                                    .build();
            Response response = chain.proceed(reWriteRequest);  
            String headValue = originalRequest.cacheControl().toString();            if (!TextUtils.isEmpty(headValue)) {
            response = response.newBuilder().header("Cache-Control", headValue).removeHeader("Pragma").build();
             }             return response;
             }

对于在请求中设置类似@Headers("Cache-Control: public,max-age=30")进行强制缓存。

OkHttp其他设置

再对OkHttp进行设置 比如 超时时间 和 缓存路径等,到此OkHttp的配置结束,一般来说就配个日志就好了。

报错信息的统一处理

看上面快速入门中有配置这个.addConverterFactory(GsonConvertFactory.create())是为了支持使用Gson解析数据,我们的错误的统一处理可以放到这里。因为每次的请求 和 响应 都会通过这个使用Gson转换为我们需要的内容

自定义ResponseConverterFactory

public class ResponseConverterFactory extends Converter.Factory {    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static ResponseConverterFactory create() {        return create(new Gson());
    }    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static ResponseConverterFactory create(Gson gson) {        return new ResponseConverterFactory(gson);
    }    private final Gson gson;    private ResponseConverterFactory(Gson gson) {        if (gson == null) throw new NullPointerException("gson == null");        this.gson = gson;
    }    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {        return new GsonResponseBodyConverter<>(gson, type);
    }    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));        return new GsonRequestBodyConverter<>(gson, adapter);
    }
}

GsonRequestBodyConverter(不做修改直接copy)

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");    private static final Charset UTF_8 = Charset.forName("UTF-8");    private final Gson gson;    private final TypeAdapter<T> adapter;
    GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {        this.gson = gson;        this.adapter = adapter;
    }    @Override public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}

GsonResponseBodyConverter(这里做统一错误处理)
对于服务器返回的失败 抛出对应异常,并且添加对JSONObject的类型装换支持。

@Override
    public T convert(ResponseBody value) throws IOException {        String response = value.string();        try {            //ResultResponse 只解析result字段
            ResultResponse resultResponse = gson.fromJson(response, ResultResponse.class);            T responseBody = getResponseBody(response);            if (resultResponse.isSuccess()){               return responseBody;
            } else {                //ErrResponse 将msg解析为异常消息文本
                throw new ApiException(resultResponse.getErrorCode(), resultResponse.getErrorMsg(),responseBody);
            }
        } finally {
        }
    }    private T getResponseBody(String response){        if(type instanceof Class){            Class clazz = (Class) type;            if(clazz.equals(JSONObject.class)){//如果返回类型 为JsonObject
                try {                    return (T) new JSONObject(response);
                } catch (JSONException e) {

                }
            }            if(clazz.equals(JSONArray.class)){                try{                    return (T) new JSONArray(response);
                }catch (JSONException e){

                }
            }
        }        return gson.fromJson(response, type);

然后ResponseConverterFactory 替代原来的GsonConvertFactory现在对于服务器返回的错误会抛出异常。

使用自定义的ApiSubscriber对所有异常进行处理

public abstract class ApiSubscriber<T> extends Subscriber<T> {/**
     * 对 onError进行处理
     * @param e
     */
    @Override
    public void onError(Throwable e) {
        Throwable throwable = e;        /**
         * 获取根源 异常
         */
        while (throwable.getCause() != null){
            e = throwable;
            throwable = throwable.getCause();
        }        if(e instanceof HttpException){//对网络异常 弹出相应的toast
            HttpException httpException = (HttpException) e;            if(TextUtils.isEmpty(httpException.getMessage())){
                ToastUtils.toast(R.string.error_net_fail);
            }else {
                String errorMsg = httpException.getMessage();                if(TextUtils.isEmpty(errorMsg)){
                    ToastUtils.toast(R.string.error_net_fail);
                }else {
                    ToastUtils.toast(errorMsg);
                }

            }
        }else if(e instanceof ApiException){//服务器返回的错误
            onResultError((ApiException) e);
        }else if(e instanceof JsonParseException
                || e instanceof JSONException
                || e instanceof ParseException){//解析异常
            ToastUtils.toast(R.string.error_net_parse);
        }else if(e instanceof UnknownHostException){
           ToastUtils.toast(R.string.error_network_is_not_available);
        }else if(e instanceof SocketTimeoutException) {
            ToastUtils.toast(R.string.error_net_timeout);
        }else {//未知错误
            if(DeviceUtils.isNetworkAvailable(GlobalData.getContext())){
                ToastUtils.toast(R.string.error_inner_error);
                e.printStackTrace();//对于未知错误进行打印,大部分为程序逻辑错误
            }else {
                ToastUtils.toast(R.string.error_network_is_not_available);
            }
        }
    }    /**
     * 服务器返回的错误
     * @param ex
     */
    protected  void onResultError(ApiException ex){        //default 打印 服务器返回
        String msg = ex.getMessage();        if(TextUtils.isEmpty(msg)){
            ToastUtils.toast("服务器未返回具体错误信息");
        }else {
            ToastUtils.toast(ex.getMessage());
        }        if(ApiException.TOKEN_INVAILD == ex.getErrCode()){
            RxBus.getDefault().post(new ReLoginEvent());
        }
    }
}

这里对常见类型异常使用Toast输出提示信息,对于服务器返回错误打印服务器的错误信息,对于token失效的错误,使用RxBus(类似EventBus)发出事件 ,之后会进行重写登陆的操作。

尝试使用

网络请求不会使用主线程,所以修改一下.addCallAdapterFactory(RxJavaCallAdapterFactory.create())改成默认在io()线程.addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))

下面是一个拉取token的简单使用示例:

RetrofitManager.getApiService().fetchToken()                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new ApiSubscriber<JSONObject>(){                    public void onNext(JSONObject jsonObject){
                    }
                })

结语

因为要配合使用Rxjava 最好先学习一遍Rxjava的使用

这样基本功能就齐全了,可以开始正式的开发工作了。关于Api接口定义可以看下Retrofit2+RxJava+Gson 使用补充

原文链接:http://www.apkbus.com/blog-822724-68248.html

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP