打造终极MVP+Retrofit2+okhttp3+Rxjava2网络请求,开发实用,简约,由于篇幅字数原因 本章讲解服务器返回类型不统一而引发的解析失败问题,开发中可能会遇到实体类定义的是某种类型(如double,int),但返回的是null或者字符串而解析失败
抓住人生中的一分一秒,胜过虚度中的一月一年!
前言
目前较火的网络请求其中有MVP+Retrofit2+okhttp3+Rxjava2,于是我也加入了使用行列,在网上找了许多案例,实际代码开发中解决了一些所谓的坑,总结了些内容与大家共享一下,有不足的地方希望大家提出我将进行再次完善。
实现目标
1、格式化数据不规范【格式化int类型数据】
2、格式化数据不规范【格式化Long类型数据】
3、格式化数据不规范【格式化Double类型数据】
4、格式化数据不规范【格式化String类型数据】
5、格式化数据不规范【格式化Null类型数据】
首先Retrofit创建
(1).导包
//网络请求 compile 'com.squareup.okhttp3:okhttp:3.9.1' compile 'com.squareup.retrofit2:retrofit:2.3.0' //ConverterFactory的Gson依赖包 compile 'com.squareup.retrofit2:converter-gson:2.3.0' //CallAdapterFactory的Rx依赖包 compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
(2).添加格式化工具方法(使用在.addConverterFactory(GsonConverterFactory.create(buildGson())))
/** * 增加后台返回""和"null"的处理 * 1.int=>0 * 2.double=>0.00 * 3.long=>0L * * @return */ public static Gson buildGson() { if (gson == null) { gson = new GsonBuilder() .registerTypeAdapter(Integer.class, new IntegerDefaultAdapter()) .registerTypeAdapter(int.class, new IntegerDefaultAdapter()) .registerTypeAdapter(Double.class, new DoubleDefaultAdapter()) .registerTypeAdapter(double.class, new DoubleDefaultAdapter()) .registerTypeAdapter(Long.class, new LongDefaultAdapter()) .registerTypeAdapter(long.class, new LongDefaultAdapter()) .registerTypeAdapter(String.class, new StringNullAdapter()) .create(); } return gson; }
(3).retrofit代码实现
/** * File descripition: 创建Retrofit * * @author lp * @date 2018/6/19 */ public class ApiRetrofit { public final String BASE_SERVER_URL = BaseContent.baseUrl; private String TAG = "ApiRetrofit %s"; private static ApiRetrofit apiRetrofit; private Retrofit retrofit; private ApiServer apiServer; private static Gson gson; private static final int DEFAULT_TIMEOUT = 15; public ApiRetrofit() { OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); httpClientBuilder .cookieJar(new CookieManger(App.getContext())) //这块是添加的管理cookie方法 .addInterceptor(interceptor)//日志拦截 .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .retryOnConnectionFailure(true);//错误重联 retrofit = new Retrofit.Builder() .baseUrl(BASE_SERVER_URL) .addConverterFactory(GsonConverterFactory.create(buildGson()))//添加json转换框架buildGson()可加可不加 //支持RxJava2 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(httpClientBuilder.build()) .build(); apiServer = retrofit.create(ApiServer.class); } public static ApiRetrofit getInstance() { if (apiRetrofit == null) { synchronized (Object.class) { if (apiRetrofit == null) { apiRetrofit = new ApiRetrofit(); } } } return apiRetrofit; } public ApiServer getApiService() { return apiServer; } /** * 请求访问quest * response拦截器 */ private Interceptor interceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); long startTime = System.currentTimeMillis(); Response response = chain.proceed(chain.request()); long endTime = System.currentTimeMillis(); long duration = endTime - startTime; MediaType mediaType = response.body().contentType(); String content = response.body().string(); // analyzeJson("data", "", content); Logger.wtf(TAG, "----------Request Start----------------"); printParams(request.body()); Logger.e(TAG, "| " + request.toString() + "===========" + request.headers().toString()); Logger.json(content); Logger.e(content); Logger.wtf(TAG, "----------Request End:" + duration + "毫秒----------"); return response.newBuilder() .body(ResponseBody.create(mediaType, content)) .build(); } }; /** * 请求参数日志打印 * * @param body */ private void printParams(RequestBody body) { if (body != null) { Buffer buffer = new Buffer(); try { body.writeTo(buffer); Charset charset = Charset.forName("UTF-8"); MediaType contentType = body.contentType(); if (contentType != null) { charset = contentType.charset(UTF_8); } String params = buffer.readString(charset); Logger.e(TAG, "请求参数: | " + params); } catch (IOException e) { e.printStackTrace(); } } } }
对返回数据格式化处理
1.对double类型处理,返回“”,或“null”,动态更改为默认值0.00,新建DoubleDefaultAdapter类
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonSyntaxException; import java.lang.reflect.Type; /** * File descripition: 对返回值为空处理 * * @author Administrator * @date 2018/5/21 */ public class DoubleDefault0Adapter implements JsonSerializer<Double>, JsonDeserializer<Double> { @Override public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为double类型,如果后台返回""或者null,则返回0.00 return 0.00; } } catch (Exception ignore) { } try { return json.getAsDouble(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
2.对int类型处理,返回“”,或“null”,动态更改为默认值0,新建DoubleDefaultAdapter类
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonSyntaxException; import java.lang.reflect.Type; /** * File descripition:double=> * * @author Administrator 对返回值为空处理 * @date 2018/5/21 */ public class IntegerDefaultAdapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> { @Override public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为int类型,如果后台返回""或者null,则返回0 return 0; } } catch (Exception ignore) { } try { return json.getAsInt(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
3.对Long类型处理,返回“”,或“null”,动态更改为默认值0,新建DoubleDefaultAdapter类
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.JsonSyntaxException; import java.lang.reflect.Type; /** * File descripition:long=> * * @author Administrator 对返回值为空处理 * @date 2018/5/21 */ public class LongDefault0Adapter implements JsonSerializer<Long>, JsonDeserializer<Long> { @Override public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("") || json.getAsString().equals("null")) {//定义为long类型,如果后台返回""或者null,则返回0 return 0l; } } catch (Exception ignore) { } try { return json.getAsLong(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
double int long三大类型处理完毕
重点说一下String类型
4、根据上边其他类型处理代码可以看出,String也就是把上述类中代码改成String就可以了,答案是可以的,如下,处理的内容为如果服务器返回字符串类型“null”,我们将其格式化成“”,空类型,但是我们为什么不直接写,请往下看
/** * File descripition:String=> * * @author Administrator 对返回值为空处理 * @date 2018/5/21 */ public class StringDefaultConverter implements JsonSerializer<String>, JsonDeserializer<String> { @Override public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { if (json.getAsString().equals("null")) { return ""; } } catch (Exception ignore) { } try { return json.getAsJsonPrimitive().getAsString(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } } @Override public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } }
(2)但是有种比较常见的不规范数据返回,为null,不是字符串的"null",是这个null,如果返回null,会进入到上边这个类吗,经过测试,返回null的直接跳过,所以出现了个问题,null到底是什么类型?
通过读源码可知,我们可以自定义TypeAdapter,将其放入facotries中,并且gson在解析json时使用对应的TypeAdapter来的,而我们手动添加的TypeAdapter会优先于预设的TypeAdapter被使用。
于是乎找到了一种其他方法来解决这个问题
5、我们新建个类来集成TypeAdapter,这样就便优先于预设的TypeAdapter
public class StringNullAdapter extends TypeAdapter<String> { @Override public String read(JsonReader reader) throws IOException { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return "";//原先是返回Null,这里改为返回空字符串 } String jsonStr = reader.nextString(); if(jsonStr.equals("null")) { return ""; }else { return jsonStr; } } @Override public void write(JsonWriter writer, String value) throws IOException { if (value == null) { writer.nullValue(); return; } writer.value(value); } }
定义的类型为String,这样为null的情况会都归这个类来处理,但是String的所有情况也会走里边的方法,所以为了同样的类型不执行俩遍,String和null都在此类处理,就没必要写上边那个方法了, 处理所有情况为返回null,或字符串"null",格式化为"" 空
String 和null情况处理完成
最后,祝大家开发顺利!