Android Retrofit 自定义GsonConverterFactory

在项目开发中,后台返回的格式没有统一返回格式(成功和失败的返回格式不一致)。
案例说明:
登录业务json(成功时)

{
    "code": 0,
    "message": "登录成功",
    "data": {
        "name": "admin",
        "token": "ad987810544564310"
    }
}

登录业务json(失败时)

{
    "code": 0,
    "message": "登录成功",
    "data": ""      
}

细心的朋友可能已经发现了问题所在。成功的时候返回的Object,而失败的时候返回的String。这样就会造成json解析异常了。我们一般的配置Retrofit如下所示。

  Retrofit retrofit = new Retrofit.Builder()
                .client(getOkHttpClient())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();

GsonConverterFactory这个类解析失败,就会造成错误了。所有我们要自定义GsonConverterFactory类来解决上面的问题。

1、MyGsonConverterFactory类
public class MyGsonConverterFactory extends Converter.Factory {

  public static MyGsonConverterFactory create() {
    return create(new Gson());
  }


  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static MyGsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new MyGsonConverterFactory(gson);
  }

  private final Gson gson;

  private MyGsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new MyGsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new MyGsonRequestBodyConverter<>(gson, adapter);
  }
}
2、MyGsonRequestBodyConverter类
public class MyGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
  private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
  private static final Charset UTF_8 = Charset.forName("UTF-8");

  private final Gson gson;
  private final TypeAdapter<T> adapter;

  MyGsonRequestBodyConverter(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());
  }
}
3、MyGsonResponseBodyConverter类
// 方法一
public class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    MyGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {

        String json = value.string();
        //第一次解析
        BaseBean obj = GsonUtils.json2Bean(json, BaseBean.class);
        if (!obj.isSuccess()) {
            //如果是服务端返回的错误码,则抛出自定义异常
            throw new ApiException(obj.getStatus(), obj.getMsg());
        }
        //第二次解析
        T  result = adapter.fromJson(json);
        value.close();
        return result;


        //原生的代码(RxJava中的代码)
//        JsonReader jsonReader = gson.newJsonReader(value.charStream());
//        try {
//            T result = adapter.read(jsonReader);
//            if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
//                throw new JsonIOException("JSON document was not fully consumed.");
//            }
//            return result;
//        } finally {
//            value.close();
//        }
    }
}

// 方法二
public class BaseResponse{
    public int code;
    public String msg;
}

final class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> {

    private final TypeAdapter<T> adapter;

    GsonResponseBodyConverter(TypeAdapter<T> adapter) {
        this.adapter = adapter;
    }

    @Override
    public Object convert(ResponseBody value) throws IOException {
        try {
            BaseResponse response = (BaseResponse) adapter.fromJson(value.charStream());
            if (response.getCode() == 200) {
                // success
                return response.getResults();
            } else {
                // 特定 API 的错误,在相应的 onError 的方法中进行处理
                throw new ApiException(response.getCode(), response.getMessage());
            }
        } finally {
            value.close();
        }

        return null;
    }
}
调用方式
 Retrofit retrofit = new Retrofit.Builder()
                .client(getOkHttpClient())
//                .addConverterFactory(GsonConverterFactory.create())   //替换调之前的,采用下面的方式即可
                .addConverterFactory(MyGsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(BASE_URL)
                .build();
另外附上json解析工具类:
public class GsonUtils {

    private static Gson mGson = new Gson();

    public static <T> T json2Bean(String json, Class<T> clazz) {
        try {
            return mGson.fromJson(json, clazz);
        } catch (Exception e) {
            LogUtils.e("GsonUtils:"+e.toString());
            return null;
        }
    }
 }

————————————————
转载于:https://blog.csdn.net/weixin_42273922/article/details/105947197

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Retrofit是一个用于在Android应用中进行网络请求的库。它通过简化网络请求的过程,提供了一种方便的方式来与后台服务器进行通信。 在Retrofit中,首先需要创建一个RetrofitService类。这个类负责配置Retrofit的基础URL和创建Retrofit实例。可以通过调用RetrofitService的create方法来创建具体的服务接口实例。这个服务接口定义了与后台服务器进行通信的方法。 在使用Retrofit时,可以通过Converter来将服务器返回的数据转换成Java对象。Retrofit支持多种转换器,可以根据数据的格式选择合适的转换器。 通过调用Retrofit的execute方法或enqueue方法可以发送网络请求。execute方法将请求发送到后台并即时返回结果,而enqueue方法将请求放入请求队列中,并在请求完成后通过Callback回调返回结果。 综上所述,Android中使用Retrofit进行网络请求的步骤包括:配置Retrofit的基础URL、创建服务接口实例、定义请求方法、选择合适的转换器、发送网络请求并处理响应。 引用: : 这段代码展示了如何在Android中使用Retrofit进行网络请求。 : 这段代码展示了创建Retrofit实例和服务接口实例的方式。 : 这段代码展示了最初使用Retrofit的方式,其中包括设置基础URL和创建Retrofit实例的步骤。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [android retrofit 从无知到入门](https://blog.csdn.net/shop_and_sleep/article/details/123526236)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值