我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android怎么使用Retrofit实现自定义Converter解析接口

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android怎么使用Retrofit实现自定义Converter解析接口

本篇内容介绍了“Android怎么使用Retrofit实现自定义Converter解析接口”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

不知道你们在使用Retrofit访问后台接口时返回的数据是否是一样的格式,比如登录接口,在我们输入密码成功或错误的时候后台返回的数据格式是不同的,这样我们在添加GsonConverterFactory解析后台数据时由于后台会返回两种不同的数据所以会导致Gson解析失败的错误信息。这里以自己项目的登录接口为例子记录下自己的解决方案。

登录成功和失败的两种数据格式:

{"success":false,"code":-1,"msg":"密码错误","data":"密码错误"}
{"success":true,"code":1,"msg":"操作成功","data":{"JXHDAPIToken":"1ccf7b01ed544882aacda365c8f620d2"}}

从上面数据中我们可以发现后台返回的数据只有data中的数据是不一样,其他几个字段都是一样的。这个时候我们可以将几个相同字段抽取出来,通过修改GsonConverterFactory来实现解析不同数据。

修改GsonConverterFactory:

我们只需要点击进入GsonConverterFactory的源码中看看它的代码,这里面我们只需要修改返回的GsonResponseBodyConverter对象。

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

所以我们再点击进入GsonResponseBodyConverter中查看它的代码结构:

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {  private final Gson gson;  private final TypeAdapter<T> adapter;  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {    this.gson = gson;    this.adapter = adapter;  }  @Override public T convert(ResponseBody value) throws IOException {    JsonReader jsonReader = gson.newJsonReader(value.charStream());    try {      return adapter.read(jsonReader);    } finally {      value.close();    }  }}

我们是无法直接在GsonResponseBodyConverter里面直接进行修改的,所以我们可以自定义一个MyGsonResponseBodyConverter类:

final class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody,T>{    private Gson gson;    private Type type;    public MyGsonResponseBodyConverter(Gson gson, Type type) {        this.gson = gson;        this.type = type;    }    @Override    public T convert(ResponseBody value) throws IOException {        String response = value.string();        try {            BaseBean baseBean = gson.fromJson(response,BaseBean.class);            if (!baseBean.isSuccess()) {                throw new DataResultException(baseBean.getMsg(),baseBean.getCode());            }            return gson.fromJson(JsonUtils.getData(response),type);        }finally {            value.close();        }    }}

这里面我们通过自己抽取出来的BaseBean去判断当前接口返回的字段success,如果为true的情况下我们正常返回数据即可,为false的情况我们通过自定义DataResultException异常类将其抛出。

public class BaseBean {    private boolean success;    private int code;    private String msg;    public boolean isSuccess() {        return success;    }    public void setSuccess(boolean success) {        this.success = success;    }    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }}

通过DataResultException获取successfalse的情况下返回的数据:

public class DataResultException extends IOException {    private String msg;    private int code;    public DataResultException(String msg, int code) {        this.msg = msg;        this.code = code;    }    public DataResultException(String message, String msg, int code) {        super(message);        this.msg = msg;        this.code = code;    }    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }}

这个时候我们对GsonConverterFactory的修改就基本完成了,但是我们要使用它的时候还需要在自定义MyGsonConverterFactoryMyGsonRequestBodyConverter两个类。

public class MyGsonRequestBodyConverter<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;    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());    }

这里主要是为了将之前自定义的MyGsonResponseBodyConverter添加进去,而MyGsonRequestBodyConverter这个类和GsonRequestBodyConverter源码内容是一样的,我们直接将内容copy过来即可。

public final class MyGsonConverterFactory extends Converter.Factory {    public static MyGsonConverterFactory create() {        return create(new Gson());    }    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) {        return new MyGsonResponseBodyConverter<>(gson,type);    }    @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);    }}

我们只需要将MyGsonConverterFactory替换之前的GsonConverterFactory即可:addConverterFactory(MyGsonConverterFactory.create())

这个时候我们再去调用之前的登录接口,当我们登录失败的时候会进入onError方法中,这个时候我们就可以判断是否抛出的是我们自定义的异常,如果是的话,那我们就可以获得当前的msgcode值从而去进行一些操作:

RetrofitUtils.getInstance().getApi().login()                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new Subscriber<LoginResult>() {                    @Override                    public void onSubscribe(Subscription s) {                    }                    @Override                    public void onNext(LoginResult loginResult) {                    }                    @Override                    public void onError(Throwable t) {                     if (t instanceof DataResultException) {                         DataResultException resultException = (DataResultException) t;                         Log.d(TAG, "Code: " + resultException.getCode() + "Message:" + resultException.getMessage());                       }                    }                    @Override                    public void onComplete() {                    }                });

这里我们可以对Subscriber进行一下封装,要不我们每次请求都需要去进行判断显得很是繁琐:

public abstract class MySubscriber<T> implements Subscriber<T> {    @Override    public void onSubscribe(Subscription s) {        s.request(Long.MAX_VALUE);    }    @Override    public void onComplete() {    }    @Override    public void onError(Throwable t) {        //这里面根据自己项目需求进行操作,比如code判断。        if (t instanceof DataResultException) {            DataResultException resultException = (DataResultException) t;            Log.d(TAG, "Code: " + resultException.getCode() + "Message:" + resultException.getMessage());        }    }

封装后我们只会调用onNext的方法,当然我们如果需要其他操作的话也可以将其他几个方法重写:

RetrofitUtils.getInstance().getApi().login()                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .subscribe(new MySubscriber<LoginResult>() {                    @Override                    public void onNext(LoginResult loginResult) {                       //登录成功                    }                });

“Android怎么使用Retrofit实现自定义Converter解析接口”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android怎么使用Retrofit实现自定义Converter解析接口

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android怎么使用Retrofit实现自定义Converter解析接口

本篇内容介绍了“Android怎么使用Retrofit实现自定义Converter解析接口”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!不知
2023-07-05

Android使用Retrofit实现自定义Converter解析接口流程详解

Retrofit是一个RESTful的HTTP网络请求框架的封装,网络请求的工作本质上是OkHttp完成,而Retrofit仅负责网络请求接口的封装
2023-03-12

解析Android中使用自定义字体的实现方法

1、Android系统默认支持三种字体,分别为:“sans”, “serif”, “monospace 2、在Android中可以引入其他字体 。 代码如下:
2022-06-06

Flask利用自定义接口实现mock应用详解

后端接口已提供,前端需要依赖后端接口返回的数据进行前端页面的开发,如何配合前端?这篇就来介绍一下Flask如何利用自定义接口实现mock应用,需要的可以参考一下
2023-03-06

java中Comparable接口排序怎么实现自定义

今天就跟大家聊聊有关java中Comparable接口排序怎么实现自定义,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。实例如下所示:class Student implements
2023-05-31

ContentProvider怎么在Android应用中实现自定义

这篇文章给大家介绍ContentProvider怎么在Android应用中实现自定义,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1,创建一个数据库帮助类,归根结底都是它在操作数据库。代码如下:package com.
2023-05-31

jquery.validationEngine自定义验证使用怎么实现

要实现自定义验证规则,可以按照以下步骤操作:在 jQuery Validation Engine 的配置中,添加自定义验证规则的定义。例如:$.fn.validationEngineLanguage.allRules.myCustomRu
2023-10-25

Android应用中怎么实现自定义状态栏

这篇文章给大家介绍Android应用中怎么实现自定义状态栏,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、目标:Android5.0以上二、步骤1、在res-values-colors.xml下新建一个RGB颜色
2023-05-31

使用Android自定义控件实现滑动解锁九宫格

本文概述: 滑动解锁九宫格的分析: 1、需要自定义控件; 2、需要重写事件onTouchEvent(); 3、需要给九个点设置序号和坐标,这里用Map类就行; 4、需要判断是否到滑到过九点之一,并存储滑到过的点的序号,而且需要一个
2022-06-06

Feign怎么利用自定义注解实现路径转义

本篇内容主要讲解“Feign怎么利用自定义注解实现路径转义”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Feign怎么利用自定义注解实现路径转义”吧!背景近期由于项目中需要,所以需要通过Feig
2023-07-02

怎么使用Serializable接口来自定义PHP中类的序列化

这篇文章主要讲解了“怎么使用Serializable接口来自定义PHP中类的序列化”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用Serializable接口来自定义PHP中类的序列化
2023-06-20

SpringBoot使用自定义注解实现数据脱敏过程详细解析

这篇文章主要介绍了SpringBoot自定义注解之脱敏注解详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-02-15

在Android开发中使用Toast怎么实现自定义布局简单示例

在Android开发中使用Toast怎么实现自定义布局简单示例?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。首先加载一个自定义的布局LayoutInflater
2023-05-31

怎么使用mybatisplus自带QueryWrapper自定义sql实现复杂查询

这篇文章主要介绍“怎么使用mybatisplus自带QueryWrapper自定义sql实现复杂查询”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用mybatisplus自带QueryWrap
2023-07-04

怎么在Android中通过自定义view实现滑动解锁效果

怎么在Android中通过自定义view实现滑动解锁效果?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。自定义view如下@SuppressLint("ClickableVi
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录