为什么OkHttp请求httpresponse返回json 返回的不是json 数据

Android的okhttp的post请求,php返回json数据。以及遇到的okhttp dispatcher问题,和json解析遇到的问题 - CSDN博客
Android的okhttp的post请求,php返回json数据。以及遇到的okhttp dispatcher问题,和json解析遇到的问题
在build.gradle文件引入:
compile ‘com.squareup.okhttp3:okhttp:3.6.0’
compile ‘com.squareup.okio:okio:1.11.0’
注意:如果没有引入okio的jar包是会报okhttp dispacther错误的,而且还要注意在回调的onResponse()方法中,只能调用一次:response.body().string(),具体原因请看:
post请求:
String json = "{\n" +
"\"operation\" : \"register\"
, \"mobile_phone\" : \"" + input_account + "\""
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url("http://45.78.12.140/art/login/login.php")
.post(requestBody)
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
public void onFailure(Call call, IOException e) {
Log.e(TAG , "onFailure: " + e);
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String jsonData = response.body().string();
parseJSONWithGSON(jsonData );
private void parseJSONWithGSON(String jsonData) {
Gson gson = new Gson();
Test t = gson.fromJson(jsonData, Test.class);
Gson gson = new Gson();
usersList = gson.fromJson(jsonData, new TypeToken&List&Test&&() {}.getType());
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
附上php服务器主要代码:
require_once('mysql_connect.php');
$json = file_get_contents("php://input");
$data = json_decode($json, true);
$sql = "select * from ecs_users where mobile_phone=?";
$stmt = $pdo-&prepare($sql);
$res = $stmt-&execute(array(""));
if($res == false)
echo $pdo-&errorCode();
echo '&br /&';
$errInfo = $pdo-&errorInfo();
print_r($errInfo);
while($row = $stmt-&fetch(PDO::FETCH_ASSOC))
$user_name = $row["user_name"];
$password = $row["password_new"];
$json = array(
'name' =& $user_name ,
'age' =& $password
$json_send = array();
$json_send[] =
'name' =& $user_name ,
'age' =& $password
echo json_encode($json , 128);
okhttp学习参考:
php返回json数据参考:
本文已收录于以下专栏:
相关文章推荐
【关键词】
Android 多点触控
如何获取单个触摸点的位置,多个触摸点的位置又如何获取呢?如何根据触摸点的位置,确定触摸点是否在 view 上?
【效果图】
概述使用过OkHttp的童鞋们都知道,同步execute(),异步enqueue()。
那么如果做到同步异步的呢,其实我们发送的同步/异步请求都会在Dispatcher中管理其状态。
Android 4.4之后,HttpURLConnection底层实现已被OkHttp替换。可以见得OkHttp的性能已经被Google所认同。对于为何会想深入了解该库的原因:因为它的最底层走到了ja...
上一节说到,发送一个请求会到RealCall的execute()和enqueue(CallBack callBack) 方法中,首先看一下这俩个方法的实现。@Override public Respo...
今天踩过的大坑........
这是一段使用okhttp进行post请求的代码
OkHttpClient client = new OkHttpClient();
Request...
第一篇博客,写的很差,希望大家多多指教!
本文采用okhttp库获取聚合网提供的免费接口数据,完成一个手机号码归属地查询功能。
其请求接口格式如下:
数据返回结果:
首先添加gson和okht...
转载请标明出处:
http://blog.csdn.net/lmj/article/details/;
本文出自:【张鸿洋的博客】
要传递一个数组到 PHP后台去, 参数是那数组类型的
经过查找 发现OKhttp3 只支付两种类型的参数   String 和 File  (查找的是OkHttpRequestB...
php实现post接口 接收android客户端json数据 存储数据库 并返回json大纲实现php端存储数据库类
实现php端接收post数据
实现php端返回json数据实现android ...
前面两篇文章介绍了基于okHttp的post、get请求,以及文件的上传下载,今天主要介绍一下如何和Json解析一起使用?如何才能提高开发效率?
     okHttp相关文章地址:
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)手动缓存Retrofit+OkHttp响应体,不再局限于Get请求缓存 - CSDN博客
手动缓存Retrofit+OkHttp响应体,不再局限于Get请求缓存
转载请标明出处:
本文出自:【iGoach的博客】
这篇博客是接着上一篇博客,没看过的,建议看完上一篇再来看这篇。在上一篇博客中仅仅是简单的讲解了OkHttp的缓存问题,主要是通过http协议里面的control-cache控制缓存,而且是仅仅只能是Get请求才能缓存,如果Post请求OkHttp会让response返回null,同时报504错误,也就是没缓存。okhttp为什么要这样做呢?通过查看缓存的文件,我们可以发现,OkHttp缓存的是整个http请求的信息,所以这就和http协议有关系了。在RESTful API里面,我们把Get请求理解为从服务端查询数据,Post请求理解为更新服务端数据,而http协议里面缓存通常只适用于idempotent request,也就是Get请求,为什么只适应Get请求?我们都知道Get请求url结合提交参数是唯一标示,而Post请求的参数是在http的body体里面,是可变的,无法成为唯一的标示。但是,我们在项目中基本上每一个接口都要提交基本参数,一般用的都是Post请求。Get请求还不太安全,请求的路径大小还有限制。既然OkHttp有限制。那么我们可以自己手动缓存。
android的缓存处理
既然要手动缓存,那么我们就要来看看android里面手动缓存有哪些。主要有两种方式,一种是sqlite缓存,一种是文件缓存。
sqlite缓存
目前有很多第三方sqlite框架,比如可以结合GreenDao来做缓存,一个缓存对应一个表。把url路经,下载时间,过期时间等信息都存放到数据库。然后把url做为请求的唯一标示,在有网的情况下,判断当前请求url缓存是否存在,存在就要移除数据库里面的缓存,然后缓存新的缓存,在没有网络的情况下,判断缓存是否过期,然后进行数据库操作。从这里我们可以看出,数据库操作还是比较频繁的,一不留神,就会出现应用性能问题,ANR问题,指针问题。而且android数据库是放在/data/data/&包名&/databases/目录下,它会占用应用内存的,一但缓存很多的话,就要及时去清理缓存,很麻烦。
为什么说文件缓存更好呢?如果SD存在的话,我们可以把缓存放在SD的/data/data/&包名&/cache目录下,不存在SD的话,再放在/data/data/&包名&下面。即使内存再多,也不会影响应用的内置应用空间。文件缓存一般都会通过DiskLruCache实现,DiskLruCache是硬盘缓存,即使应用进程结束了,缓存还是存在的。当应用卸载时,改目录的数据也会清除掉,不会留下残余数据。DiskLruCache缓存,没有什么过期时间之说,只要它存在文件里面,我们就可以随时去读取它。下面我们就用DiskLruCache对Retrofit+OkHttp的响应体进行缓存。这里我们只缓存json数据。
DiskLruCache的使用方法
获取DiskLruCache对象
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
不能直接通过new的方法创建,要通过调用DiskLruCache.open()这个方法获取,有四个参数,File指的是缓存的存储路径,一般优先存储于SD卡的 /sdcard/Android/data/&包名&/cache 路径下,如果SD卡不存在,再存在/data/data/&包名&/cache 这个路径下,判断代码如下
private File getDiskCacheDir(Context context, String uniqueName)
String cacheP
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| !Environment.isExternalStorageRemovable())
//如果SD卡存在通过getExternalCacheDir()获取路径,
cachePath = context.getExternalCacheDir().getPath();
//如果SD卡不存在通过getCacheDir()获取路径,
cachePath = context.getCacheDir().getPath();
//放在路径 /.../data/&application package&/cache/uniqueName
return new File(cachePath + File.separator + uniqueName);
appVersion指的是版本号,可以指应用的版本号,valueCount指的就是一个key对应多少个文件,一般我们指定1个文件,一对一使得后面更好获取。maxSize指的是缓存的最大大小,一般传入5M或者10M就够了。
首先我们先获取一个DiskLruCache.Editor对象,代码如下
public DiskLruCache.Editor editor(String key)
key = Utils.hashKeyForDisk(key);
DiskLruCache.Editor edit = mDiskLruCache.edit(key);
if (edit == null)
Log.w(TAG, "the entry spcified key:" + key + " is editing by other . ");
return edit;
} catch (IOException e)
e.printStackTrace();
return null;
首先进行的是Utils.hashKeyForDisk(key),也就是通过MD5生成唯一的请求标示,这样就可以通过key来获取DiskLruCache.Editor实例。获取到实例后就可以获取到OutputStream,然后通过BufferedWriter写入,如下代码
public void put(String key, String value)
DiskLruCache.Editor edit = null;
BufferedWriter bw = null;
edit = editor(key);
if (edit == null) return;
OutputStream os = edit.newOutputStream(0);
bw = new BufferedWriter(new OutputStreamWriter(os));
bw.write(value);
edit.commit();
} catch (IOException e)
e.printStackTrace();
edit.abort();
} catch (IOException e1)
e1.printStackTrace();
if (bw != null)
bw.close();
} catch (IOException e)
e.printStackTrace();
首先是通过key获取DiskLruCache.Snapshot实例,然后得到InputStream,如下代码
public InputStream get(String key)
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(Utils.hashKeyForDisk(key));
if (snapshot == null)
Log.e(TAG, "not find entry , or entry.readable = false");
return null;
return snapshot.getInputStream(0);
} catch (IOException e)
e.printStackTrace();
return null;
然后就是InputStreamReader读取,如下代码
public String getAsString(String key) {
InputStream inputStream = null;
inputStream = get(key);
if (inputStream == null) return null;
String str = null;
str = Util.readFully(new InputStreamReader(inputStream, Util.UTF_8));
} catch (IOException e) {
e.printStackTrace();
inputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
return str;
static String readFully(Reader reader) throws IOException
StringWriter writer = new StringWriter();
char[] buffer = new char[1024];
int count;
while ((count = reader.read(buffer)) != -1)
writer.write(buffer, 0, count);
return writer.toString();
reader.close();
然后就是删除操作
public boolean remove(String key)
key = Utils.hashKeyForDisk(key);
return mDiskLruCache.remove(key);
} catch (IOException e)
e.printStackTrace();
return false;
直接remove掉就ok了。
DiskLruCache的封装
从Github里面搜索DiskLruCache,可以看到鸿洋大神的,它主要是把diskcache封装成和AsimpleCache框架一样,挺好用的。
使用方法如下(来源于)
put(String key, Bitmap bitmap)
put(String key, byte[] value)
put(String key, String value)
put(String key, JSONObject jsonObject)
put(String key, JSONArray jsonArray)
put(String key, Serializable value)
put(String key, Drawable value)
editor(String key).newOutputStream(0);
String getAsString(String key);
JSONObject getAsJson(String key)
JSONArray getAsJSONArray(String key)
&T& T getAsSerializable(String key)
Bitmap getAsBitmap(String key)
byte[] getAsBytes(String key)
Drawable getAsDrawable(String key)
InputStream get(String key);
这里我只是保存响应的json,只用到
put(String key, String value)
String getAsString(String key);
两个方法,至于key使用请求参数生成的MD5做为唯一的标示。
下面就使用这个DiskLruCache封装进行手动缓存,DiskLruCache的源码和封装代码可以去鸿洋的github上。
HRetrofitNetHelper代码的修改
基于上一篇博客的HRetrofitNetHelper对象。进行代码修改,修改点如下
去除OkHttp的cache缓存配置
去除mUrlInterceptor的拦截器
改在call的onresponse里面进行操作
enqueueCall方法配置成链式编程配置
然后再贴上全部的代码,注意几个修改点就好了。
public class HRetrofitNetHelper implements HttpLoggingInterceptor.Logger {
public static HRetrofitNetHelper mI
public Retrofit mR
public OkHttpClient mOkHttpC
public HttpLoggingInterceptor mHttpLogI
private BasicParamsInterceptor mBaseParamsI
Context mC
DiskLruCacheHelper diskLruCacheH
public static final String BASE_URL = "http://192.168.1.102:8080/GoachWeb/";
private Action1&String& onNextA
private HRetrofitNetHelper(Context context){
this.mContext =
createSubscriberByAction();
mGson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
mHttpLogInterceptor = new HttpLoggingInterceptor(this);
mHttpLogInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Map&String,String& tempParams = getBaseParams();
mBaseParamsInterceptor = new BasicParamsInterceptor.Builder()
.addParamsMap(tempParams)
diskLruCacheHelper = new DiskLruCacheHelper(mContext);
} catch (IOException e) {
e.printStackTrace();
mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(12, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(mHttpLogInterceptor)
.addInterceptor(mBaseParamsInterceptor)
mRetrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(mGson))
.client(mOkHttpClient)
public static HRetrofitNetHelper getInstance(Context context){
if(mInstance==null){
synchronized (HRetrofitNetHelper.class){
if(mInstance==null){
mInstance =
new HRetrofitNetHelper(context);
public &T& T getAPIService(Class&T& service) {
return mRetrofit.create(service);
public static final class enqueueCall{
boolean isC
RetrofitCallBack retrofitCallB
HRetrofitNetHelper mRetrofitNetH
private Context mC
private DiskLruCacheHelper diskLruCacheH
public enqueueCall(HRetrofitNetHelper retrofitNetHelper){
isCache = false;
this.mRetrofitNetHelper = retrofitNetH
this.mContext = retrofitNetHelper.mC
this.mGson = retrofitNetHelper.mG
this.diskLruCacheHelper = retrofitNetHelper.diskLruCacheH
public &D& enqueueCall call(Call&BaseResp&D&& call){
this.call =
return this;
public enqueueCall clazz(Type clazz){
this.clazz =
return this;
public &D& enqueueCall retrofitCallBack(RetrofitCallBack&D& retrofitCallBack){
this.retrofitCallBack = retrofitCallB
return this;
public enqueueCall isCache(boolean isCache){
this.isCache = isC
return this;
public &D& enqueueCall start(){
call.enqueue(new Callback&BaseResp&D&&() {
public void onResponse(Call&BaseResp&D&& call, Response&BaseResp&D&& response) {
Request request = call.request();
String requestUrl = call.request().url().toString();
BaseResp&D& resp = response.body() ;
RequestBody requestBody = request.body();
Charset charset = Charset.forName("UTF-8");
String key="";
if(method.equals("POST")){
MediaType contentType = requestBody.contentType();
if (contentType != null) {
charset = contentType.charset(Charset.forName("UTF-8"));
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
} catch (IOException e) {
e.printStackTrace();
key = buffer.readString(charset);
buffer.close();
key = requestU
Log.d("zgx","response==========key"+key);
if(!TextUtils.isEmpty(requestUrl)){
if(requestUrl.contains("LoginDataServlet")) {
if (Looper.myLooper() == null) {
Looper.prepare();
mRetrofitNetHelper.createObservable("现在请求的是登录接口");
if(NetUtil.checkNetwork(mContext)!=NetUtil.NO_NETWORK){
if(resp==null){
if(retrofitCallBack!=null)
retrofitCallBack.onFailure("暂无数据");
if (resp.getResultCode() == 2000 || resp.getResultCode() == 2001 || resp.getResultCode() == 2002) {
Toast.makeText(mContext,"code====="+resp.getResultCode(),Toast.LENGTH_SHORT).show();
if (resp.getResultCode() == 200&&response.code()==200) {
if(retrofitCallBack!=null){
String cacheResponse = mGson.toJson(resp);
diskLruCacheHelper.remove(key);
Log.d("zgx","response========cacheResponse"+cacheResponse);
diskLruCacheHelper.put(key,cacheResponse);
retrofitCallBack.onSuccess(resp);
if(retrofitCallBack!=null)
retrofitCallBack.onFailure(resp.getErrMsg());
String json = diskLruCacheHelper.getAsString(key);
if(json==null){
Toast.makeText(mContext, "没有缓存!", Toast.LENGTH_SHORT).show();
if(retrofitCallBack!=null){
retrofitCallBack.onFailure("没有缓存!");
if(clazz==null){
throw new IllegalArgumentException("请先配置clazz");
resp = mGson.fromJson(json,clazz);
if(retrofitCallBack!=null){
retrofitCallBack.onSuccess(resp);
public void onFailure(Call&BaseResp&D&& call, Throwable t) {
if(retrofitCallBack!=null){
retrofitCallBack.onFailure(t.toString());
return this;
public void clearCache() throws IOException {
diskLruCacheHelper.delete();
主要修改的地方,上面基本上都注释到了,这里没有做缓存的过期时间,有网的情况下,还是保持数据的实时性,没网的情况下才会去读取缓存。
API修改为Post请求
ILoginService.class
public interface ILoginService {
@FormUrlEncoded
@POST("LoginDataServlet")
Call&BaseResp&RegisterBean&& userLogin(@Field("username") String username, @Field("password") String password);
INewsService.class
public interface INewsService {
@FormUrlEncoded
@POST("NewsDataServlet")
Call&BaseResp&News&NewItem&&& userNews(@Field("userId") String userId);
这里主要是测试这两个接口
请求修改为链式编程
登录请求修改代码如下
首先实现回调接口
//传入成功回调的BaseResp&的泛型T为RegisterBean
implements HRetrofitNetHelper.RetrofitCallBack&
然后是Call请求配置
final Call&BaseResp&RegisterBean&& repos = loginService.userLogin(username,password);
new HRetrofitNetHelper
.enqueueCall(HRetrofitNetHelper.getInstance(this))
.call(repos)
.retrofitCallBack(this)
.isCache(true)
.clazz(new TypeToken&BaseResp&RegisterBean&&(){}.getType())
然后实现两个回调方法
public void onSuccess(BaseResp&RegisterBean& baseResp) {
Date date = baseResp.getResponseTime();
if(baseResp.getData().getErrorCode()==1){
Toast.makeText(getBaseContext(),"登录成功",Toast.LENGTH_SHORT).show();
Toast.makeText(getBaseContext(),"用户不存在",Toast.LENGTH_SHORT).show();
mDialog.dismiss();
public void onFailure(String error) {
Log.d("zgx","onFailure======"+error);
mDialog.dismiss();
如果新闻页也要缓存,那么代码同理修改如下。
private void loadData(){
INewsService newService = retrofitNetHelper.getAPIService(INewsService.class)
Log.d("zgx","mUserId====="+mUserId)
final Call&BaseResp&News&NewItem&&& repos = newService.userNews(mUserId)
new HRetrofitNetHelper.enqueueCall(HRetrofitNetHelper.getInstance(this))
.call(repos)
.retrofitCallBack(this)
.isCache(true)
.clazz(new TypeToken&BaseResp&News&NewItem&&&(){}.getType())
这样就缓存了登录接口的数据和新闻页面的数据。
下面就来测试下,只缓存登录接口。测试结果为有网的情况下,根据上面代码知道登录成功会弹出登录成功的Toast,并且会生成缓存文件,没有网络的情况下会去读取缓存,并且还是会弹出Toast提示,登录失败不弹。效果如下
接下来我们再看下没有缓存的效果,代码只要修改不配置
HRetrofitNetHelper.enqueueCall(HRetrofitNetHelper.getInstance(this))
.call(repos)
.retrofitCallBack(this)
然后就来看效果,有网的情况下应该为登录成功,没网的情况下,提示没有缓存,效果如下
Get请求效果同理。同样可以得到这样的效果,感兴趣的可以去试下。
最后配置3个权限
android:name="android.permission.INTERNET" /&
android:name="android.permission.ACCESS_NETWORK_STATE" /&
android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&
总体感觉Retrofit+OkHttp框架用起来还是很方便的。特别是响应式编程,用的特别爽。还有就是Retrofit的源码设计的特别完美。不过在这里,用RxAndroid用的还是比较少,相信以后会用的越来越多,而且现在谷歌的agera响应式编程也出来了。
本文已收录于以下专栏:
相关文章推荐
本文主要介绍了如何在一个老项目中替换将旧的Http框架替换成OkHttp3或Retrofit2。并介绍了使用OkHttp3和Retrofit2发送GET和POST请求的代码示例。介绍了Retrofit...
volley配置okhttp,以及引发的超时问题
Okhttp作为现在最火的一个网络请求框架,已经有无数牛人给出了工具类等等。
例如: 
鸿洋大神的 Android 一个改善的okHttp封装库 和 Android
OkHttp完全解析 ...
OkHttp现在很火呀。于是上个星期就一直在学习OkHttp框架,虽然说起来已经有点晚上手了,貌似是2013年就推出了。但是现在它版本更加稳定了呀。这不,说着说着,OkHttp3.3版本在这几天又发布...
很多时候,我们要测试某个网络请求,这时候就得有一个快速上手的网络请求框架方便使用。GitHub链接:/mocn26169/QuickHttpRequest使用步骤下...
OKhttp的基本应用  
      在讲OKhttp之前我们先说一下http的的出现及发展
HTTP协议结构    
 http的组成是请求头,请求体,响应头,响应体。
请求头:本次请求的客户端;...
现有这样一个要求,使用Retorfit+okhttp需要在有网的时候能够连接服务器,读取相关信息;在没网络断开的时候需要读取Okhttp的缓存来达到离线的效果。
基于上述的需求,可以使用Okhttp...
okhttp缓存使用,基于okhttp3.5.0
再也不用担心记不住RxJava中的操作符了,RxJava操作符大全,需要用时Ctrl+F一下,还有使用例子哦。
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。Android M(6.x)使用OkHttp包解析和发送JSON请求的教程
作者:总李写代码
字体:[ ] 类型:转载 时间:
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
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/ charset=utf-8");
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//开启一个线程,做联网操作
new Thread() {
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)
//发送请求获取响应
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统一泛型解析,与一些Java的反射机制来解析泛型对象Class&?&:
1.首先我们声明一个TypeInfo.java类用来封装泛型相关属性
import java.lang.reflect.A
import java.lang.reflect.GenericArrayT
import java.lang.reflect.ParameterizedT
import java.lang.reflect.T
public class TypeInfo {
//Type泛型对象类型
private Class&?& componentT
//Type所属对象类型
private Class&?& rawT
private TypeInfo(Class&?& rawType, Class&?& componentType) {
ponentType = componentT
this.rawType = rawT
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 =
if (type instanceof ParameterizedType) {
//返回 Type 对象,表示声明此类型的类或接口。
this.rawType = (Class&?&) ((ParameterizedType) type).getRawType();
//getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组。
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
ponentType = (Class&?&) actualTypeArguments[0];
// typeReference=new TypeReference&Map&componentType,componentType&&(){};
} else if (type instanceof GenericArrayType) {
//返回 Type 对象,表示声明此类型的类或接口。
this.rawType = Array.
// 表示一种元素类型是参数化类型或者类型变量的数组类型
ponentType = (Class&?&) ((GenericArrayType) type).getGenericComponentType();
ponentType = (Class&?&)
public Type getType() {
public Class&?& getComponentType() {
return componentT
public Class&?& getRawType() {
return rawT
2.声明ReqClassUtils.java类 用于通过反射机制获取泛型对象的TypeInfo
import java.lang.reflect.ParameterizedT
import java.lang.reflect.T
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]);
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]);
3.接下来重点来了,声明一个json解析工具类ReqJsonUtils.java,主要用于通过TypeInfo相关属性进行不同类型的json解析
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONE
import com.alibaba.fastjson.JSONO
import java.lang.reflect.A
import java.util.C
import java.util.HashM
import java.util.M
import static com.alibaba.fastjson.JSON.parseO
public class ReqJsonUtils {
//基本类型映射关系Map
private static final Map primitiveWrapperTypeMap = new HashMap(8);
//添加基本类型
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
* @throws JSONException
public static &T& T parseHttpResult(TypeInfo type, String jsonData) throws JSONException {
// 处理Void类型的返回值
if (Void.class.isAssignableFrom(type.getComponentType())) {
//获取当前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 =
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) jsonD
// 接口的返回类型如果是简单类型,则会封装成为一个json对象,真正的对象存储在value属性上
if (isPrimitiveOrWrapper(componentType)) {
result = (T) parseObject(jsonData);
//处理自定义对象
result = (T) parseObject(jsonData, componentType);
* 判断是否是基本数据类型
* @param clazz
public static boolean isPrimitiveOrWrapper(Class clazz) {
return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
* 判断是否是基本数据类型
* @param clazz
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&() {
public void onReqSuccess(String result) {
request_tv.setText(result);
public void onReqFailed(String errorMsg) {
3.支持类型
new ReqCallBack&List&Object&&();//集合collection
new ReqCallBack&Map&String, User&&();//map
new ReqCallBack&Void&();//Void
new ReqCallBack&Long&();//基础类型
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 response返回json对象 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信