I don't know if the data you return when using Retrofit to access the background interface is the same format. For example, when logging in to the interface, the data returned in the background is different when we enter the password successfully or incorrectly, so we are addingGsonConverterFactory
When parsing background data, the background will return two different data, so it will causeGson
The error message that failed to parse. Here we use the login interface of our project as an example to record your own solution.
Two data formats for successful and failed login:
{"success":false,"code":-1,"msg":"Error password","data":"Error password"}
{"success":true,"code":1,"msg":"The operation is successful","data":{"JXHDAPIToken":"1ccf7b01ed544882aacda365c8f620d2"}}
From the above data, we can find that the data returned in the background is different only in data, and the other fields are the same. At this time, we can extract several identical fields and modify themGsonConverterFactory
to parse different data.
Modify GsonConverterFactory:
We just need to click to enterGsonConverterFactory
Look at its code in the source code, we only need to modify the returned oneGsonResponseBodyConverter
Object.
@Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = ((type)); return new GsonResponseBodyConverter<>(gson, adapter);
So let's click to enterGsonResponseBodyConverter
Check its code structure:
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final Gson gson; private final TypeAdapter<T> adapter; GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) { = gson; = adapter; } @Override public T convert(ResponseBody value) throws IOException { JsonReader jsonReader = (()); try { return (jsonReader); } finally { (); } } }
We can't be directlyGsonResponseBodyConverter
It is modified directly, so we can customize oneMyGsonResponseBodyConverter
kind:
final class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody,T>{ private Gson gson; private Type type; public MyGsonResponseBodyConverter(Gson gson, Type type) { = gson; = type; } @Override public T convert(ResponseBody value) throws IOException { String response = (); try { BaseBean baseBean = (response,); if (!()) { throw new DataResultException((),()); } return ((response),type); }finally { (); } } }
We extracted it from ourselvesBaseBean
To determine the fields returned by the current interfacesuccess
, iftrue
In the case offalse
We customize the situationDataResultException
The exception class throws it.
public class BaseBean { private boolean success; private int code; private String msg; public boolean isSuccess() { return success; } public void setSuccess(boolean success) { = success; } public int getCode() { return code; } public void setCode(int code) { = code; } public String getMsg() { return msg; } public void setMsg(String msg) { = msg; } }
passDataResultException
Getsuccess
forfalse
The data returned in the case:
public class DataResultException extends IOException { private String msg; private int code; public DataResultException(String msg, int code) { = msg; = code; } public DataResultException(String message, String msg, int code) { super(message); = msg; = code; } public String getMsg() { return msg; } public void setMsg(String msg) { = msg; } public int getCode() { return code; } public void setCode(int code) { = code; } }
At this time we areGsonConverterFactory
The modification is basically completed, but we still need to customize it when we want to use itMyGsonConverterFactory
andMyGsonRequestBodyConverter
Two categories.
public class MyGsonRequestBodyConverter<T> implements Converter<T, RequestBody> { private static final MediaType MEDIA_TYPE = ("application/json; charset=UTF-8"); private static final Charset UTF_8 = ("UTF-8"); private final Gson gson; private final TypeAdapter<T> adapter; MyGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) { = gson; = adapter; } @Override public RequestBody convert(T value) throws IOException { Buffer buffer = new Buffer(); Writer writer = new OutputStreamWriter((), UTF_8); JsonWriter jsonWriter = (writer); (jsonWriter, value); (); return (MEDIA_TYPE, ()); }
This is mainly for customizing itMyGsonResponseBodyConverter
Add it, andMyGsonRequestBodyConverter
This class andGsonRequestBodyConverter
The source code content is the same, we just copy the content directly.
public final class MyGsonConverterFactory extends { 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) { = 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 = ((type)); return new MyGsonRequestBodyConverter<>(gson, adapter); } }
We just need toMyGsonConverterFactory
Replace the previous oneGsonConverterFactory
Just:addConverterFactory(())
At this time, we will call the previous login interface. When our login fails, we will enteronError
In the method, at this time we can determine whether the exception is thrown. If so, we can obtain the current one.msg
andcode
Value to perform some operations:
().getApi().login() .subscribeOn(()) .observeOn(()) .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; (TAG, "Code: " + () + "Message:" + ()); } } @Override public void onComplete() { } });
Here we canSubscriber
It is very complicated to encapsulate it, otherwise we need to make judgments every time we request:
public abstract class MySubscriber<T> implements Subscriber<T> { @Override public void onSubscribe(Subscription s) { (Long.MAX_VALUE); } @Override public void onComplete() { } @Override public void onError(Throwable t) { //This is done according to your project needs, such as code judgment. if (t instanceof DataResultException) { DataResultException resultException = (DataResultException) t; (TAG, "Code: " + () + "Message:" + ()); } }
We will only call after encapsulationonNext
Of course, if we need other operations, we can also rewrite several other methods:
().getApi().login() .subscribeOn(()) .observeOn(()) .subscribe(new MySubscriber<LoginResult>() { @Override public void onNext(LoginResult loginResult) { //Login successfully } });
Okay, it's over here. Before I knew it, I felt that time passed so quickly. I always felt that I didn't have enough time. I felt that there were still many things that I needed to learn by myself, but I was always inexplicably lazy. Haha, I hope I can continue to work hard to grow slowly on the road ahead.
This is the article about the detailed explanation of the process of implementing custom Converter parsing interfaces for Android using Retrofit. For more relevant content on Android custom Converter parsing interfaces, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!