Android通用网络请求解析框架.7(同步请求,公共部分)
2017-01-06 18:21
615 查看
笔者将通过11篇博客对个人开源框架进行讲解,本篇为第7篇,讲解同步请求,公共部分。
开源库github地址 https://github.com/qq296216078/Android-Universial-NetFrame
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
在第一篇中,需求讲解的时候,我们希望得到数据时,已经回到主线程
这种情况,也是最常见的情况,就是我们通常所说的异步请求。
但是在实际项目中,有时候不需要回到主线程,比如下面这种情况
开发者需要一些在后台定时跑的任务,固定一分钟进行几个接口的请求,这些请求在返回时不需要在主线程中有操作,或者开发者想自己用Handler来返回到主线程。
这个时候,也就是通常所说的同步请求,如果继续使用异步请求的代码,是可能出现问题的。
因为异步请求的代码中有些部分是不需要的
1.不需要创建AsyncTask
2.不需要创建Handler
第1点,开发者发起同步请求的时候,必须是自己已经处在子线程中,大家都知道ui线程中进行网络请求是会出错的。
第2点,在第1点的前提下创建的Handler,原先实现的代码是会报错的,通常会是这个错
因为在非ui线程中创建的Handler,并不能将消息传送到ui线程,需要加入一些Looper相关的代码才可以。而同步请求不需要将结果返回到ui线程,所以这里的代码也是不需要的。
因为第2点的问题,所以在子线程中进行同步请求时,直接使用异步请求代码,会出现异常。那该怎么办呢?
这里有两个解决方案:
1.在之前的代码的许多地方加上一些参数,在调用的时候逐层传递进去,框架内层根据参数判断要进行哪些操作
2.重新模仿之前的代码,实现一套同步请求的代码
笔者采用了第2种办法。原因也有两点:
1.如果采用第1种办法,框架中的代码将会变得更复杂,提供给开发者使用的入口也会变得复杂。这导致了在编程和使用上都变麻烦了。
2.如果采用第2种办法,并不是所有代码都要重写,只要关键部分进行修改就可以了,与线程操作无关的代码,可以不要修改,所以实现起来也不麻烦。
在这里,我们先不急着实现同步请求的内步代码,我们先假设已经实现了相应代码,直接开始使用。
那么之前的需求,实现起来会是这样的
url1和url2的请求是按顺序下来的,也就是说url1必须是请求结束了,要么回调了onSuccess,要么回调了onError,才会开始url2请求。这看起来非常的奇怪,同步执行的代码,看不出来他们的顺序性。再看看这样的需求
url2的请求需要依赖url1请求的结果。如果用NetHelper实现,代码看起来就非常的奇怪了
需要嵌套多层,同步执行的代码,因为回调的原因,让开发者看不明白执行顺序。而且回调方法里面的参数,并不能直接给下面的代码使用,必须要用到全局变量才行,回调方法中如果要使用外部的变量,也需要全局变量,或者定义为final的局部变量。明明是按顺序执行的代码,但这代码结构却让人感到非常蛋疼。对于按顺序同步执行的代码,笔者不能忍受用这种回调的方式来实现。
有没有好的办法解决呢?显然是有的,就像上面的代码一样,request1()的请求是有返回值的,而不是通过回调来返回。
那么,如果NetHelper.get方法具有返回值,就好办了,我们就可以这样完成需求
看起来好像是可以,我们甚至可以用NetTempListener,不需要实现回调,让代码更简洁
可是问题又来了,这里的get方法只能返回boolean类型,如果需求是根据url1请求的结果解析后的Bean的某一个属性来判断是否要进行url2请求,那么又要写一个不同返回值的get方法,而且内部逻辑又麻烦了许多。需求都是不断变化的,返回值要根据需求做不同的变化。之前我们做异步请求,将不同的返回结果进行归类,成功和失败时的返回值有不同的回调。而现在一个方法只有一个返回值,我们要怎样在不改代码的情况下,让这个返回值适合各种情况呢?
可能有些人想到了用Map,对,Map是可以,但是Map里面的key值是哪些,取出来后每个value都要强转,确实够麻烦。
有现成的东西为什么不用呢?对了,就是NetRetBean,我们让同步请求时,就返回NetRetBean。
返回NetRetBean的好处我想大家能够明白的,因为这个类中封装了请求成功和失败时所有情况的数据,包括解析后的,还有自定义解析的数据。
拿到NetRetBean返回值后,根据CallbackCode判断请求是否成功,
如果成功,NetRetBean中的外层数据也都不为null
如果成功,NetRetBean的内层数据也不为null
如果失败,可以根据CallbackCode进行判断是哪种原因导致的
在使用上,应该是这样的
这里,我们为NetHelper添加了getSync方法,表明使用同步请求。
做的是同步请求,所以强转操作必须开发者自己来进行,因为serverObject是Object类型的。
之前笔者也想过将NetRetBean中serverObject的类型写成泛型,根据传入不同的监听器和泛型,自动转成相应的类型。但是后来因为自定义解析器时返回的数据可能不只有一个,可能是非常多个的,最后还是得用到NetRetBean中的serverObjectMap,所以放弃了将serverObject类型写成泛型的写法。
那么现在,之前的需求,根据url1请求的结果来判断是否进行url2请求,也就变成这样了
使用上代码好像没有比返回boolean简洁多少,但是NetRetBean好在可以通用,基本上所有返回结果的需求都包含了。
内部代码要如何实现呢?既然要返回值,那就应该逐层进行返回。看看代码,或许就更清楚了。
先从NetHelper入手,异步请求的代码利用NetExcutor进行get或者post操作,然后在返回时回调NetListener。
在这里,我们希望有数据返回,那么,直接在get或者post方法处进行返回,显然是非常合理的
对比之前的代码,仅仅是让get方法具有返回值而已。
接下来我们实现内部代码。根据之前的分析,在涉及线程相关的代码的地方,不再使用之前的类,而是重新写一套代码。
而NetExcutor类,里面就有AsyncTask,那就把原来的AsyncTask给去掉,换上另一个名字SyncNetExcutor
与NetExcutor的代码相比,有以下几处修改:
1.最大的变化就是去掉了AsyncTask,而在get和post两个入口不创建线程直接进行request请求。
2.NetListener换成了SyncNetListener。
3.get和post方法变成有返回值的了,返回值是NetRetBean,其返回值是从SyncNetListener处得来的。
4.增加了getString和postString方法,他返回的是String类型,是网络请求的直接返回结果。
先来看看SyncNetListener
只是把之前的返回类型void改成NetRetBean,因为需要返回值嘛
因为内部代码的修改,外部调用也要做修改才行,我们接着来看看NetHelper入口吧
使用起来也就是调用SyncNetExcutor,然后再把返回值给开发者。
getSync和postSync返回类型是NetRetBean,是网络请求解析后的结果。
getStringSync和postStringSync返回的是String类型,是网络请求的直接返回结果。
如果你直接使用getStringSync或者postStringSync,是非常简单的
这两个方法只是简单的返回网络请求的数据,并没有对数据进行任何解析,而且返回的string是可能为null的。
如果我们直接调用NetHelper.getSync,会是这样的
这里的回调并不是最后执行的地方。我们看看SyncNetExcutor中的部分代码
调用监听器来实现成功和失败时候的处理,而且都要返回一个NetRetBean,然后再把这个NetRetBean返回给上层。
所以最后执行的地方是getSync方法的返回,然后再往下执行,只是请求的过程当中调用了这两个回调中的一个。
从代码结构上,还是不能容忍的,而且,还他还没真正的去解析,还要开发者自己去完成解析和错误处理。
如果在回调的解析方法中直接返回null,那么返回的NetRetBean中的众多属性还是为null。
所以仅仅做到这里,同步请求的代码实现还没完成。解析和错误处理的代码,要在框架内部进行处理才合理。
回忆一下,异步请求时外层解析和错误处理是在NetHandleListener类里面,
而且,同步请求除了AsyncTask外,还有另一个与线程相关的代码,就是Handler,也在NetHandleListener中,
那么NetHandleListener也需要改写。
NetHandleListener继承自NetListener,所以我们实现一个SyncNetHandleListener,继承自SyncNetListener
与NetHandleListener相比,SyncNetHandleListener显得更加简洁,这里的代码有以下几处改变:
1.最大的变化就是去掉了Handler,因为无需将解析后的结果返回到ui线程
2.由于1的变化,handleResult方法将直接返回NetRetBean,而不是通过Handler把数据传递给ui线程
3.onReceivedRet是具有返回值的,因为sendSuccess里面需要返回结果
4.去掉了onSuccess和onError方法,因为这里不需要再回调,而是直接返回结果
第2点中的handleResult方法,虽然只有一行,但是笔者为了让代码与异步请求的保持相似的风格,还是保留了这个方法。
公共部分的代码,还包括RequestUtil,HttpUtil,还有一些相关的类,这些类的代码都没有做修改。
这个时候,如果我们再调用NetHelper.getSync,使用上SyncNetHandleListener,会是这样的
和使用SyncNetListener一样,还是存在代码执行顺序模糊的问题。还有内层数据的解析,需要开发者自己来完成。
如果在onReceivedRet回调的解析方法中直接返回null,那么在返回的NetRetBean的内层数据还是为null。
不过我们把外层的数据在SyncNetHandleListener类里面进行解析了,公共部分的代码实现完成了。
分支部分,即内层解析部分的代码还需要一定的篇幅,所以将其放到下一篇中去讲解。
至此,同步请求公共部分讲解完成。
下一篇,将讲解同步请求分支部分
Android通用网络请求解析框架.8(同部请求,分支部分)
开源库github地址 https://github.com/qq296216078/Android-Universial-NetFrame
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
在第一篇中,需求讲解的时候,我们希望得到数据时,已经回到主线程
NetHelper.get("url", new NetSingleBeanListener<NetUserBean>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { // 这里是ui线程 } @Override protected void onSuccess(NetUserBean userBean) { // 这里是ui线程 } });
这种情况,也是最常见的情况,就是我们通常所说的异步请求。
但是在实际项目中,有时候不需要回到主线程,比如下面这种情况
private void startRequest() { new Thread() { @Override public void run() { request1(); request2(); try { Thread.sleep(60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }
开发者需要一些在后台定时跑的任务,固定一分钟进行几个接口的请求,这些请求在返回时不需要在主线程中有操作,或者开发者想自己用Handler来返回到主线程。
这个时候,也就是通常所说的同步请求,如果继续使用异步请求的代码,是可能出现问题的。
因为异步请求的代码中有些部分是不需要的
1.不需要创建AsyncTask
2.不需要创建Handler
第1点,开发者发起同步请求的时候,必须是自己已经处在子线程中,大家都知道ui线程中进行网络请求是会出错的。
第2点,在第1点的前提下创建的Handler,原先实现的代码是会报错的,通常会是这个错
Can't create handler inside thread that has not called Looper.prepare()
因为在非ui线程中创建的Handler,并不能将消息传送到ui线程,需要加入一些Looper相关的代码才可以。而同步请求不需要将结果返回到ui线程,所以这里的代码也是不需要的。
因为第2点的问题,所以在子线程中进行同步请求时,直接使用异步请求代码,会出现异常。那该怎么办呢?
这里有两个解决方案:
1.在之前的代码的许多地方加上一些参数,在调用的时候逐层传递进去,框架内层根据参数判断要进行哪些操作
2.重新模仿之前的代码,实现一套同步请求的代码
笔者采用了第2种办法。原因也有两点:
1.如果采用第1种办法,框架中的代码将会变得更复杂,提供给开发者使用的入口也会变得复杂。这导致了在编程和使用上都变麻烦了。
2.如果采用第2种办法,并不是所有代码都要重写,只要关键部分进行修改就可以了,与线程操作无关的代码,可以不要修改,所以实现起来也不麻烦。
在这里,我们先不急着实现同步请求的内步代码,我们先假设已经实现了相应代码,直接开始使用。
那么之前的需求,实现起来会是这样的
private void startRequest() { new Thread() { @Override public void run() { NetHelper.get("url1", new NetStringListener() { @Override protected void onSuccess(String string) { } @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } } NetHelper.get("url2", new NetStringListener() { @Override protected void onSuccess(String string) { } @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } } }.start(); }
url1和url2的请求是按顺序下来的,也就是说url1必须是请求结束了,要么回调了onSuccess,要么回调了onError,才会开始url2请求。这看起来非常的奇怪,同步执行的代码,看不出来他们的顺序性。再看看这样的需求
private void startRequest() { new Thread() { @Override public void run() { if (request1()) { request2(); } } }.start(); }
url2的请求需要依赖url1请求的结果。如果用NetHelper实现,代码看起来就非常的奇怪了
private void startRequest() { new Thread() { @Override public void run() { NetHelper.get("url1", new NetStringListener() { @Override protected void onSuccess(String string) { NetHelper.get("url2", new NetStringListener() { @Override protected void onSuccess(String string) { } @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } }); } @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } }); } }.start(); }
需要嵌套多层,同步执行的代码,因为回调的原因,让开发者看不明白执行顺序。而且回调方法里面的参数,并不能直接给下面的代码使用,必须要用到全局变量才行,回调方法中如果要使用外部的变量,也需要全局变量,或者定义为final的局部变量。明明是按顺序执行的代码,但这代码结构却让人感到非常蛋疼。对于按顺序同步执行的代码,笔者不能忍受用这种回调的方式来实现。
有没有好的办法解决呢?显然是有的,就像上面的代码一样,request1()的请求是有返回值的,而不是通过回调来返回。
那么,如果NetHelper.get方法具有返回值,就好办了,我们就可以这样完成需求
private void startRequest() { new Thread() { @Override public void run() { boolean ret = NetHelper.get("url1", new NetStringListener() { @Override protected void onSuccess(String string) { } @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } }); if (ret) { NetHelper.get("url2", new NetStringListener() { @Override protected void onSuccess(String string) { } @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } }); } } }.start(); }
看起来好像是可以,我们甚至可以用NetTempListener,不需要实现回调,让代码更简洁
private void startRequest() { new Thread() { @Override public void run() { boolean ret = NetHelper.get("url1", new new NetTempListener()); if (ret) { NetHelper.get("url2", new NetTempListener()); } } }.start(); }
可是问题又来了,这里的get方法只能返回boolean类型,如果需求是根据url1请求的结果解析后的Bean的某一个属性来判断是否要进行url2请求,那么又要写一个不同返回值的get方法,而且内部逻辑又麻烦了许多。需求都是不断变化的,返回值要根据需求做不同的变化。之前我们做异步请求,将不同的返回结果进行归类,成功和失败时的返回值有不同的回调。而现在一个方法只有一个返回值,我们要怎样在不改代码的情况下,让这个返回值适合各种情况呢?
可能有些人想到了用Map,对,Map是可以,但是Map里面的key值是哪些,取出来后每个value都要强转,确实够麻烦。
有现成的东西为什么不用呢?对了,就是NetRetBean,我们让同步请求时,就返回NetRetBean。
返回NetRetBean的好处我想大家能够明白的,因为这个类中封装了请求成功和失败时所有情况的数据,包括解析后的,还有自定义解析的数据。
拿到NetRetBean返回值后,根据CallbackCode判断请求是否成功,
如果成功,NetRetBean中的外层数据也都不为null
如果成功,NetRetBean的内层数据也不为null
如果失败,可以根据CallbackCode进行判断是哪种原因导致的
在使用上,应该是这样的
private void startRequest() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url", new NetTempListener()); CallbackCode callbackCode = netRetBean.getCallbackCode(); switch (callbackCode) { case CODE_SUCCESS_REQUEST: String string = (String) netRetBean.getServerObject(); System.out.println(string); break; case CODE_ERROR_HTTP_NOT_200: case CODE_ERROR_REQUEST_EXP: case CODE_ERROR_SERVER_DATA_ERROR: case CODE_ERROR_JSON_EXP: case CODE_ERROR_UNKNOWN: default: System.out.println(netRetBean.toString()); break; } } }.start(); }
这里,我们为NetHelper添加了getSync方法,表明使用同步请求。
做的是同步请求,所以强转操作必须开发者自己来进行,因为serverObject是Object类型的。
之前笔者也想过将NetRetBean中serverObject的类型写成泛型,根据传入不同的监听器和泛型,自动转成相应的类型。但是后来因为自定义解析器时返回的数据可能不只有一个,可能是非常多个的,最后还是得用到NetRetBean中的serverObjectMap,所以放弃了将serverObject类型写成泛型的写法。
那么现在,之前的需求,根据url1请求的结果来判断是否进行url2请求,也就变成这样了
private void startRequest() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url1", new NetTempListener()); if (netRetBean.isSuccess()) { NetHelper.getSync("url2", new NetTempListener()); } } }.start(); }
使用上代码好像没有比返回boolean简洁多少,但是NetRetBean好在可以通用,基本上所有返回结果的需求都包含了。
内部代码要如何实现呢?既然要返回值,那就应该逐层进行返回。看看代码,或许就更清楚了。
先从NetHelper入手,异步请求的代码利用NetExcutor进行get或者post操作,然后在返回时回调NetListener。
在这里,我们希望有数据返回,那么,直接在get或者post方法处进行返回,显然是非常合理的
public class NetHelper { public static NetRetBean getSync(String url, boolean isWaitForToken, NetListener netListener) { NetExcutor netExcutor = new NetExcutor(); netExcutor.setUrl(url); netExcutor.setWaitForToken(isWaitForToken); netExcutor.setNetListener(netListener); return netExcutor.get(); } }
对比之前的代码,仅仅是让get方法具有返回值而已。
接下来我们实现内部代码。根据之前的分析,在涉及线程相关的代码的地方,不再使用之前的类,而是重新写一套代码。
而NetExcutor类,里面就有AsyncTask,那就把原来的AsyncTask给去掉,换上另一个名字SyncNetExcutor
package com.chenjian.net.core.sync; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.core.common.RequestType; import com.chenjian.net.request.RequestUtil; import com.chenjian.net.token.TokenUtil; /** * 网络请求处理核心类 * <p> * 作者: ChenJian * 时间: 2016.12.13 17:42 */ public class SyncNetExcutor { /** * 请求url */ private String mUrl; /** * 请求类型 */ private RequestType mRequestType; /** * post请求时的参数 */ private String mParams; /** * 是否先等待token请求成功 */ private boolean isWaitForToken; /** * 请求后的回调 */ private SyncNetListener mSyncNetListener; public void setUrl(String url) { this.mUrl = url; } private void setRequestType(RequestType requestType) { this.mRequestType = requestType; } public void setParams(String params) { this.mParams = params; } public void setWaitForToken(boolean waitForToken) { isWaitForToken = waitForToken; } public void setSyncNetListener(SyncNetListener syncNetListener) { this.mSyncNetListener = syncNetListener; } public NetRetBean get() { setRequestType(RequestType.REQUEST_TYPE_GET); return startRequest(); } public NetRetBean post() { setRequestType(RequestType.REQUEST_TYPE_POST); return startRequest(); } /** * 同步请求,直接返回 * * @return 返回 NetRetBean */ private NetRetBean startRequest() { if (isWaitForToken) { TokenUtil.waitToken(); } try { String result = request(); return mSyncNetListener.sendSuccess(result); } catch (Exception e) { e.printStackTrace(); return mSyncNetListener.sendError(e); } } public String getString() { setRequestType(RequestType.REQUEST_TYPE_GET); return startRequestString(); } public String postString() { setRequestType(RequestType.REQUEST_TYPE_POST); return startRequestString(); } /** * 同步请求,直接返回 * * @return 返回 String */ private String startRequestString() { if (isWaitForToken) { TokenUtil.waitToken(); } try { return request(); } catch (Exception e) { e.printStackTrace(); } return null; } private String request() throws Exception { String result = null; switch (mRequestType) { case REQUEST_TYPE_GET: result = RequestUtil.getRequest(mUrl); break; case REQUEST_TYPE_POST: result = RequestUtil.postRequest(mUrl, mParams); break; default: break; } return result; } }
与NetExcutor的代码相比,有以下几处修改:
1.最大的变化就是去掉了AsyncTask,而在get和post两个入口不创建线程直接进行request请求。
2.NetListener换成了SyncNetListener。
3.get和post方法变成有返回值的了,返回值是NetRetBean,其返回值是从SyncNetListener处得来的。
4.增加了getString和postString方法,他返回的是String类型,是网络请求的直接返回结果。
先来看看SyncNetListener
package com.chenjian.net.core.sync; import com.chenjian.net.bean.NetRetBean; /** * 网络请求回调核心类 * <p> * 作者: ChenJian * 时间: 2016.12.13 17:42 */ public interface SyncNetListener { /** * http请求,数据解密部分,成功 * * @param result result * @return NetRetBean */ NetRetBean sendSuccess(String result); /** * http请求,数据解密部分,失败 * * @param e e * @return NetRetBean */ NetRetBean sendError(Exception e); }
只是把之前的返回类型void改成NetRetBean,因为需要返回值嘛
因为内部代码的修改,外部调用也要做修改才行,我们接着来看看NetHelper入口吧
package com.chenjian.net.helper; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.core.async.NetExcutor; import com.chenjian.net.core.async.NetListener; import com.chenjian.net.core.sync.SyncNetExcutor; import com.chenjian.net.core.sync.SyncNetListener; import com.chenjian.net.data.NetConstants; /** * 网络请求工具类 * <p> * 作者: ChenJian * 时间: 2016.12.14 11:24 */ public class NetHelper { /** * get同步请求 * * @param url url * @param syncNetListener 监听器 * @return NetRetBean */ public static NetRetBean getSync(String url, SyncNetListener syncNetListener) { return getSync(url, NetConstants.defaultWaitForToken, syncNetListener); } /** * get同步请求 * * @param url url * @param isWaitForToken 是否等待token请求成功 * @param syncNetListener 监听器 * @return NetRetBean */ public static NetRetBean getSync(String url, boolean isWaitForToken, SyncNetListener syncNetListener) { SyncNetExcutor syncNetExcutor = new SyncNetExcutor(); syncNetExcutor.setUrl(url); syncNetExcutor.setWaitForToken(isWaitForToken); syncNetExcutor.setSyncNetListener(syncNetListener); return syncNetExcutor.get(); } /** * post同步请求 * * @param url url * @param params 参数 * @param syncNetListener 监听器 * @return NetRetBean */ public static NetRetBean postSync(String url, String params, SyncNetListener syncNetListener) { return postSync(url, params, NetConstants.defaultWaitForToken, syncNetListener); } /** * post同步请求 * * @param url url * @param params 参数 * @param isWaitForToken 是否等待token请求成功 * @param syncNetListener 监听器 * @return NetRetBean */ public static NetRetBean postSync(String url, String params, boolean isWaitForToken, SyncNetListener syncNetListener) { SyncNetExcutor syncNetExcutor = new SyncNetExcutor(); syncNetExcutor.setUrl(url); syncNetExcutor.setParams(params); syncNetExcutor.setWaitForToken(isWaitForToken); syncNetExcutor.setSyncNetListener(syncNetListener); return syncNetExcutor.post(); } /** * get同步请求,不设置监听器,直接返回数据给调用者 * * @param url url * @return String */ public static String getStringSync(String url) { return getStringSync(url, NetConstants.defaultWaitForToken); } /** * get同步请求,不设置监听器,直接返回数据给调用者 * * @param url url * @param isWaitForToken 是否等待token请求成功 * @return String */ public static String getStringSync(String url, boolean isWaitForToken) { SyncNetExcutor syncNetExcutor = new SyncNetExcutor(); syncNetExcutor.setUrl(url); syncNetExcutor.setWaitForToken(isWaitForToken); return syncNetExcutor.getString(); } /** * post同步请求,不设置监听器,直接返回数据给调用者 * * @param url url * @param params 参数 * @return String */ public static String postStringSync(String url, String params) { return postStringSync(url, params, NetConstants.defaultWaitForToken); } /** * post同步请求,不设置监听器,直接返回数据给调用者 * * @param url url * @param params 参数 * @param isWaitForToken 是否等待token请求成功 * @return String */ public static String postStringSync(String url, String params, boolean isWaitForToken) { SyncNetExcutor syncNetExcutor = new SyncNetExcutor(); syncNetExcutor.setUrl(url); syncNetExcutor.setParams(params); syncNetExcutor.setWaitForToken(isWaitForToken); return syncNetExcutor.postString(); } }
使用起来也就是调用SyncNetExcutor,然后再把返回值给开发者。
getSync和postSync返回类型是NetRetBean,是网络请求解析后的结果。
getStringSync和postStringSync返回的是String类型,是网络请求的直接返回结果。
如果你直接使用getStringSync或者postStringSync,是非常简单的
private void syncGetString() { new Thread() { @Override public void run() { String getString = NetHelper.getStringSync("url"); System.out.println(getString); String postString = NetHelper.getStringSync("url"); System.out.println(postString); } }.start(); }
这两个方法只是简单的返回网络请求的数据,并没有对数据进行任何解析,而且返回的string是可能为null的。
如果我们直接调用NetHelper.getSync,会是这样的
private void startRequest() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetListener() { @Override public NetRetBean sendSuccess(String result) { return null; } @Override public NetRetBean sendError(Exception e) { return null; } }); } }.start(); }
这里的回调并不是最后执行的地方。我们看看SyncNetExcutor中的部分代码
public NetRetBean get() { setRequestType(RequestType.REQUEST_TYPE_GET); return startRequest(); } public NetRetBean post() { setRequestType(RequestType.REQUEST_TYPE_POST); return startRequest(); } /** * 同步请求,直接返回 * * @return 返回 NetRetBean */ private NetRetBean startRequest() { if (isWaitForToken) { TokenUtil.waitToken(); } try { String result = request(); return mSyncNetListener.sendSuccess(result); } catch (Exception e) { e.printStackTrace(); return mSyncNetListener.sendError(e); } }
调用监听器来实现成功和失败时候的处理,而且都要返回一个NetRetBean,然后再把这个NetRetBean返回给上层。
所以最后执行的地方是getSync方法的返回,然后再往下执行,只是请求的过程当中调用了这两个回调中的一个。
从代码结构上,还是不能容忍的,而且,还他还没真正的去解析,还要开发者自己去完成解析和错误处理。
如果在回调的解析方法中直接返回null,那么返回的NetRetBean中的众多属性还是为null。
所以仅仅做到这里,同步请求的代码实现还没完成。解析和错误处理的代码,要在框架内部进行处理才合理。
回忆一下,异步请求时外层解析和错误处理是在NetHandleListener类里面,
而且,同步请求除了AsyncTask外,还有另一个与线程相关的代码,就是Handler,也在NetHandleListener中,
那么NetHandleListener也需要改写。
NetHandleListener继承自NetListener,所以我们实现一个SyncNetHandleListener,继承自SyncNetListener
package com.chenjian.net.listener.sync; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.core.sync.SyncNetListener; import com.chenjian.net.exp.RequestErrorException; import com.chenjian.net.exp.RespondErrorException; import com.chenjian.net.listener.common.CallbackCode; import org.json.JSONException; import org.json.JSONObject; /** * 公用网络逻辑,核心监听器。自定义监听器一般继承这个类 * <p> * 作者: ChenJian * 时间: 2016.12.15 11:12 */ abstract public class SyncNetHandleListener implements SyncNetListener { /** * 处理NetRetBean并返回。是一个中转站。本类和其子类都可以调用这个方法 * * @param netRetBean netRetBean * @return netRetBean */ protected NetRetBean handleResult(NetRetBean netRetBean) { return netRetBean; } @Override public NetRetBean sendSuccess(String result) { NetRetBean netRetBean = new NetRetBean(); try { JSONObject jsonObject = new JSONObject(result); String code = jsonObject.getString("code"); String message = jsonObject.getString("message"); String time = jsonObject.getString("time"); String data = jsonObject.getString("data"); netRetBean.setServerCode(code); netRetBean.setServerMsg(message); netRetBean.setServerTime(time); netRetBean.setServerData(data); if (code.equals("00001")) { netRetBean.setCallbackCode(CallbackCode.CODE_SUCCESS_REQUEST); netRetBean = onReceivedRet(netRetBean); } else { netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_SERVER_DATA_ERROR); } } catch (JSONException e) { e.printStackTrace(); netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_JSON_EXP); } return handleResult(netRetBean); } @Override public NetRetBean sendError(Exception exp) { exp.printStackTrace(); NetRetBean netRetBean = new NetRetBean(); netRetBean.setException(exp); try { throw exp; } catch (RespondErrorException e) { netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_HTTP_NOT_200); } catch (RequestErrorException e) { netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_REQUEST_EXP); } catch (JSONException e) { netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_JSON_EXP); } catch (Exception e) { netRetBean.setCallbackCode(CallbackCode.CODE_ERROR_UNKNOWN); } return handleResult(netRetBean); } /** * 子类根据业务区分,将netRetBean解析成list或者单个实体,或者解析成其它结果 * * @param netRetBean server返回的数据实体,data字段将在子类中解析 * @return 解析后的netRetBean * @throws JSONException 解析json异常 */ abstract protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException; }
与NetHandleListener相比,SyncNetHandleListener显得更加简洁,这里的代码有以下几处改变:
1.最大的变化就是去掉了Handler,因为无需将解析后的结果返回到ui线程
2.由于1的变化,handleResult方法将直接返回NetRetBean,而不是通过Handler把数据传递给ui线程
3.onReceivedRet是具有返回值的,因为sendSuccess里面需要返回结果
4.去掉了onSuccess和onError方法,因为这里不需要再回调,而是直接返回结果
第2点中的handleResult方法,虽然只有一行,但是笔者为了让代码与异步请求的保持相似的风格,还是保留了这个方法。
公共部分的代码,还包括RequestUtil,HttpUtil,还有一些相关的类,这些类的代码都没有做修改。
这个时候,如果我们再调用NetHelper.getSync,使用上SyncNetHandleListener,会是这样的
private void syncGetString() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetHandleListener() { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { return null; } }); } }.start(); }
和使用SyncNetListener一样,还是存在代码执行顺序模糊的问题。还有内层数据的解析,需要开发者自己来完成。
如果在onReceivedRet回调的解析方法中直接返回null,那么在返回的NetRetBean的内层数据还是为null。
不过我们把外层的数据在SyncNetHandleListener类里面进行解析了,公共部分的代码实现完成了。
分支部分,即内层解析部分的代码还需要一定的篇幅,所以将其放到下一篇中去讲解。
至此,同步请求公共部分讲解完成。
下一篇,将讲解同步请求分支部分
Android通用网络请求解析框架.8(同部请求,分支部分)
相关文章推荐
- Android通用网络请求解析框架.8(同步请求,分支部分)
- Android通用网络请求解析框架.3(代码实现,公共部分)
- Android通用网络请求解析框架.4(代码实现,分支部分)
- Android通用网络请求解析框架.1(需求,思想)
- Android通用网络请求解析框架.2(构造框架)
- Android通用网络请求解析框架.5(使用框架)
- Android通用网络请求解析框架.10(发现问题,改善)
- Android通用网络请求解析框架.11(总结)
- Android通用网络请求解析框架.6(自定义解析器)
- Android通用网络请求解析框架.9(支持第三方解析框架)
- Android网络请求框架----Okhttp3完全解析(1),使用篇
- Android网络请求框架----Okhttp3完全解析(2),封装框架
- OKHttp网络框架源码解析(一)okHttp框架同步异步请求流程和源码分析
- Android网络请求框架—OKHttp 源码解析
- android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件
- Android---Xutils3.0 网络请求框架封装(包含解析)
- android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件
- Android下网络请求数据,返回数据显示不全,解析json no value for xxx
- 教你写Android网络框架之Request、Response类与请求队列
- android中网络请求数据,解析并添加到Listview中