Android M(6.x)使用OkHttp包解析和发送JSON请求的教程

 更新时间:2016年07月13日 15:16:23   作者:总李写代码  
Android 6.0采用的SPDY支持HTTP上GZIP压缩的传输,这使得OkHttp包的功能能够进一步被利用,本文我们来总结一下Android M(6.0)使用OkHttp包解析和发送JSON请求的教程

关于Android 6.0
Android老版本网络请求:
1,HttpUrlConnection
2,Apache Http Client
Android6.0版本网络请求:
1,HttpUrlConnection
2,OkHttp
Android6.0版本废弃了老的网络请求,那么它的优势是什么呢?
1,支持SPDY,共享同一个Socket来处理同一个服务器的所有请求
2,如果SPDY不可用,则通过连接池来减少请求延时
3,无缝的支持GZIP来减少数据流量
4,缓存响应数据来减少重复的网络请求

post请求发送给服务器JSON:

我们先来看一个样例,详细的请求发送我们下面还会讲.

public class MainActivity extends AppCompatActivity {

public static final String TAG = "MainActivity";
public static final MediaType JSON=MediaType.parse("application/json; charset=utf-8");
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //开启一个线程,做联网操作
 new Thread() {
  @Override
  public void run() {

   postJson();
  }
 }.start();
}

 private void postJson() {
 //申明给服务端传递一个json串
 //创建一个OkHttpClient对象
 OkHttpClient okHttpClient = new OkHttpClient();
 //创建一个RequestBody(参数1:数据类型 参数2传递的json串)
 RequestBody requestBody = RequestBody.create(JSON, json);
 //创建一个请求对象
 Request request = new Request.Builder()
   .url("http://192.168.0.102:8080/TestProject/JsonServlet")
   .post(requestBody)
   .build();
 //发送请求获取响应
 try {
 Response response=okHttpClient.newCall(request).execute();
  //判断请求是否成功
  if(response.isSuccessful()){\
   //打印服务端返回结果
   Log.i(TAG,response.body().string());

  }
 } catch (IOException e) {
  e.printStackTrace();
 }

}

}

SPDY(读作“SPeeDY”)是Google开发的基于TCP的应用层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验。SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩。谷歌表示,引入SPDY协议后,在实验室测试中页面加载速度比原先快64%。
ZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNⅨ系统的文件压缩。我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。现今已经成为Internet 上使用非常普遍的一种数据压缩格式,或者说一种文件格式。
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来.一般对纯文本内容可压缩到原大小的40%.这样传输就快了,效果就是你点击网址后会很快的显示出来.当然这也会增加服务器的负载. 一般服务器中都安装有这个功能模块的。

JSON解析
这里我们将采用json统一泛型解析,与一些Java的反射机制来解析泛型对象Class<?>:
1.首先我们声明一个TypeInfo.java类用来封装泛型相关属性

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class TypeInfo {
 //Type泛型对象类型
 private Class<?> componentType;
 //Type所属对象类型
 private Class<?> rawType;
 //type
 private Type type;

 private TypeInfo(Class<?> rawType, Class<?> componentType) {

  this.componentType = componentType;
  this.rawType = rawType;
 }

 public static TypeInfo createArrayType(Class<?> componentType) {
  return new TypeInfo(Array.class, componentType);
 }

 public static TypeInfo createNormalType(Class<?> componentType) {
  return new TypeInfo(null, componentType);
 }

 public static TypeInfo createParameterizedType(Class<?> rawType, Class<?> componentType) {
  return new TypeInfo(rawType, componentType);
 }

 public TypeInfo(Type type) {
  this.type = type;
  if (type instanceof ParameterizedType) {
   //返回 Type 对象,表示声明此类型的类或接口。
   this.rawType = (Class<?>) ((ParameterizedType) type).getRawType();
   //getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组。
   Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
   this.componentType = (Class<?>) actualTypeArguments[0];
   // typeReference=new TypeReference<Map<componentType,componentType>>(){};

  } else if (type instanceof GenericArrayType) {
   //返回 Type 对象,表示声明此类型的类或接口。
   this.rawType = Array.class;
   // 表示一种元素类型是参数化类型或者类型变量的数组类型
   this.componentType = (Class<?>) ((GenericArrayType) type).getGenericComponentType();
  } else {
   this.componentType = (Class<?>) type;
  }
 }

 public Type getType() {
  return type;
 }

 public Class<?> getComponentType() {
  return componentType;
 }


 public Class<?> getRawType() {
  return rawType;
 }

}

2.声明ReqClassUtils.java类 用于通过反射机制获取泛型对象的TypeInfo

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class ReqClassUtils {

 public static TypeInfo getCallbackGenericType(Class<?> clazz) {
  //获得带有泛型的父类
  Type genericSuperclass = clazz.getGenericSuperclass();//Type是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
  TypeInfo type = getGetnericType(genericSuperclass);
  if (type == null) {
   Type[] genericInterfaces = clazz.getGenericInterfaces();
   if (genericInterfaces != null && genericInterfaces.length > 0) {
    type = getGetnericType(genericInterfaces[0]);
   }
  }
  return type;
 }

 private static TypeInfo getGetnericType(Type type) {
  if (type != null && type instanceof ParameterizedType) {
   //getActualTypeArguments获取参数化类型的数组,泛型可能有多个
   Type[] args = ((ParameterizedType) type).getActualTypeArguments();
   if (args != null && args.length > 0) {
    return new TypeInfo(args[0]);
   }
  }
  return null;
 }
}

3.接下来重点来了,声明一个json解析工具类ReqJsonUtils.java,主要用于通过TypeInfo相关属性进行不同类型的json解析

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static com.alibaba.fastjson.JSON.parseObject;

public class ReqJsonUtils {

 //基本类型映射关系Map
 private static final Map primitiveWrapperTypeMap = new HashMap(8);

 static {
  //添加基本类型
  primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
  primitiveWrapperTypeMap.put(Byte.class, byte.class);
  primitiveWrapperTypeMap.put(Character.class, char.class);
  primitiveWrapperTypeMap.put(Double.class, double.class);
  primitiveWrapperTypeMap.put(Float.class, float.class);
  primitiveWrapperTypeMap.put(Integer.class, int.class);
  primitiveWrapperTypeMap.put(Long.class, long.class);
  primitiveWrapperTypeMap.put(Short.class, short.class);
 }

 /**
  * 将JSON字符串转换成指定的用户返回值类型
  *
  * @param type
  * @param jsonData
  * @return
  * @throws JSONException
  */
 public static <T> T parseHttpResult(TypeInfo type, String jsonData) throws JSONException {
  // 处理Void类型的返回值
  if (Void.class.isAssignableFrom(type.getComponentType())) {
   return null;
  }
  //获取当前type的数据类型
  Class<?> rawType = type.getRawType();
  //是否是Array
  boolean isArray = rawType != null && Array.class.isAssignableFrom(rawType);
  //是否是Collection
  boolean isCollection = rawType != null && Collection.class.isAssignableFrom(rawType);
  //是否是Map
  boolean isMap = rawType != null && Map.class.isAssignableFrom(rawType);
  //获取泛型类型
  Class<?> componentType = type.getComponentType();
  //声明结果对象
  T result = null;
  if (isCollection) {//处理collection
   result = (T) JSON.parseArray(jsonData, componentType);
  } else if (isArray) {//处理array
   result = (T) JSON.parseArray(jsonData, componentType).toArray();
  } else if (isMap) {//处理Map
   result = (T) JSONObject.parseObject(jsonData, type.getType());
  } else if (componentType.isAssignableFrom(String.class)) {//处理字符串返回值
   return (T) jsonData;
  } else {
   // 接口的返回类型如果是简单类型,则会封装成为一个json对象,真正的对象存储在value属性上
   if (isPrimitiveOrWrapper(componentType)) {
    result = (T) parseObject(jsonData);
   } else {
    //处理自定义对象
    result = (T) parseObject(jsonData, componentType);
   }
  }
  return result;
 }

 /**
  * 判断是否是基本数据类型
  *
  * @param clazz
  * @return
  */
 public static boolean isPrimitiveOrWrapper(Class clazz) {
  return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
 }

 /**
  * 判断是否是基本数据类型
  *
  * @param clazz
  * @return
  */
 public static boolean isPrimitiveWrapper(Class clazz) {
  return primitiveWrapperTypeMap.containsKey(clazz);
 }
}

如何使用?
1.实现解析

 TypeInfo typeInfo = ReqClassUtils.getCallbackGenericType(callBack.getClass());
 callBack.onReqSuccess(ReqJsonUtils.parseHttpResult(typeInfo, jsonData));

2.发送请求

  HashMap<String, String> paramsMap = new HashMap<>();
  paramsMap.put("sourceType", "2");
  paramsMap.put("sourceDesc", "[Android]" + Build.VERSION.RELEASE + "[Mobel]" + Build.BRAND + " " + Build.MODEL + Build.DEVICE);
  HashMap<String, String> params = dealStringBody(paramsMap);
  RequestManager.getInstance(this).requestAsyn("xxx/actionUrl", RequestManager.TYPE_POST_JSON, params, new ReqCallBack<String>() {

   @Override
   public void onReqSuccess(String result) {
    request_tv.setText(result);
   }

   @Override
   public void onReqFailed(String errorMsg) {

   }
  });

3.支持类型

  new ReqCallBack<List<Object>>();//集合collection
  new ReqCallBack<Map<String, User>>();//map
  new ReqCallBack<Void>();//Void
  new ReqCallBack<Long>();//基础类型

 

相关文章

  • 浅谈EventBus

    浅谈EventBus

    EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service。本文对其实现原理进行系统介绍,有需要的朋友可以看下
    2016-12-12
  • 关于Android中drawable必知的一些规则

    关于Android中drawable必知的一些规则

    drawable这个东西相信大家天天都在使用,每个Android开发者都再熟悉不过了,但可能还有一些你所不知道的规则,那今天我们就来一起探究一下这些规则。
    2016-08-08
  • Android Socket服务端与客户端用字符串的方式互相传递图片的方法

    Android Socket服务端与客户端用字符串的方式互相传递图片的方法

    这篇文章主要介绍了Android Socket服务端与客户端用字符串的方式互相传递图片的方法的相关资料,需要的朋友可以参考下
    2016-05-05
  • 使用Composing builds提升Android编译速度

    使用Composing builds提升Android编译速度

    这篇文章主要介绍了使用Composing builds提升Android编译速度示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Android编程之EditText常见操作示例

    Android编程之EditText常见操作示例

    这篇文章主要介绍了Android编程之EditText常见操作,结合实例形式分析了Android EditText光标与文本操作相关技巧,需要的朋友可以参考下
    2017-03-03
  • Android 修改app图标和名称的方法

    Android 修改app图标和名称的方法

    下面小编就为大家分享一篇Android 修改app图标和名称的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • Android如何在一个TextView中设置不同字体大小、不同字体颜色封装

    Android如何在一个TextView中设置不同字体大小、不同字体颜色封装

    在开发过程中遇到过这样一种业务,有很多单行文本字体,字符串中每一部分的字体样式、大小、颜色都不相同,传统的做法是放多个TextView以达到效果,这篇文章主要介绍了android在一个TextView中设置不同字体大小、不同字体颜色封装,需要的朋友可以参考下
    2024-07-07
  • Android 实现抢购倒计时功能的示例

    Android 实现抢购倒计时功能的示例

    这篇文章主要介绍了Android 实现抢购倒计时功能的示例,帮助大家更好的理解和学习使用Android开发,感兴趣的朋友可以了解下
    2021-03-03
  • Android字符串转Ascii码实例代码

    Android字符串转Ascii码实例代码

    这篇文章主要介绍了Android字符串转Ascii码的方法,大家参考使用
    2013-11-11
  • Android自定义View实现圆形切图效果

    Android自定义View实现圆形切图效果

    这篇文章主要为大家详细介绍了Android自定义View实现圆形切图效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12

最新评论