Android通用网络请求解析框架.8(同步请求,分支部分)
2017-01-06 18:23
525 查看
笔者将通过11篇博客对个人开源框架进行讲解,本篇为第8篇,讲解支持同步请求,分支部分。
开源库github地址 https://github.com/qq296216078/Android-Universial-NetFrame
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
上一篇中我们已经完成了同步请求公共部分的代码实现,核心监听器的代码是这样的
使用上SyncNetHandleListener,会是这样的
还是存在代码执行顺序模糊的问题。还有内层数据的解析,需要开发者自己来完成。
如果在onReceivedRet回调的解析方法中直接返回null,那么在返回的NetRetBean的内层数据还是为null。
为了不让使用者来实现内层数据的解析,所以就应该在框架内部实现内层数据的解析。
那应该怎样在框架内部进行解析呢?学异步请求就好了,继承SyncNetHandleListener,来看看子类中是怎样解析数据的
这里的handleResult是父类的方法,根据之前的代码,父类这个方法只是将NetRetBean原封不动的返回。
因为父类中定义抽象方法onReceivedRet时需要返回值,所以这里需要将内层数据进行解析,然后再返回。
还有一个变化,因为本类不存在抽象方法,所以本类也不是抽象类了,不要在类的前面加上abstract。
对比一下异步请求的代码实现
可以看到,同步请求的时候,因为父类没有onSuccess方法,也不需要回调,所以同步请求代码实现起来更简单,只是将解析后的结果进行返回就可以了。
正如上面所说,同步请求的Listener不是抽象类,不要加abstract修饰类,
其它监听器也需要做类似的修改,继承SyncNetHandleListener,我们实现了SyncNetSingleBeanListener
再实现SyncNetListBeanListener
可以看到,同步请求分支部分的代码和异步请求时差不多,只是父类不一样,还有最后需要将结果进行返回,而不是回调。
到此,框架中同步请求的代码都已经添加完成,可以开始使用了
getStringSync返回的是最原始的数据,没有经过解析的,他不需要传入监听器参数。
getSync返回的是NetRetBean,传入的监听器类型的不同,NetRetBean中serverObject类型也会不同。当然这里需要开发者自己取出来进行强转。
笔者一开始想把serverObject对象的类型变成泛型,后来发现如果是自定义监听器进行同步请求时,一个泛型对象不够通用,还是得用到serverObjectMap属性才行。
回顾上一篇中的需求,根据url1请求的结果判断是否请求url2,我们可以这样实现
这样的话,代码的执行顺序就很清晰了,返回值的方式也非常符合同步请求的需求,代码看起来简单明了。
我们接着再来使用其它的Listener来完成同步请求。
假设服务端返回的数据是这样的:
NetUserBean的代码与之前的一样,没有改变
开始使用
居然报错了
再细看异常信息
重点在于这两行
我们再看看NetBaseBeanUtil的41行代码
很明显的看出来了,aClass.getGenericSuperclass后,是一个Object类型,不能强转为ParameterizedType。
可是之前的SyncNetStringListener为什么没有报错呢?因为SyncNetStringListener并没有用到NetBaseBeanUtil,只是将数据解析为String类型,而不需要使用到NetBaseBeanUtil方法来获取Bean。
那又为什么异步请求时都没问题,而在这个地方就有问题呢?
回忆一下第4篇中提到的java泛型去参数化的概念,我们再来看看NetBaseBeanUtil的代码
正如注释所说,这里的aClass的父类必须是带泛型的,而在使用异步请求的时候,因为需要回调,通常的做法是new一个Listener为内部类。而内部类实际上编译器会先定义一个类继承于他,然后再将那个类传入当参数。而同步请求,而直接new一个对象出来,并没有使用他的子类。一起来通过代码对比一下
异步请求我们使用内部类,其实get方法的第二个参数的类型,是NetSingleBeanListener的子类
同步请求时,我们直接生成一个SyncNetStringListener的对象
在两个Listener中,我们在使用NetBaseBeanUtil时,都调用了下面这一行代码
getClass()非常重要,
在NetSingleBeanListener中,如果是他的子类调用了这个方法,那么返回的是他的子类
在SyncNetSingleBeanListener中,只是本类调用了这个方法,所以返回的是这个类本身
而这个时候,在NetBaseBeanUtil的getBean方法中,需要用到aClass.getGenericSuperclass,对传入的class对象进行操作,
如果传入的aClass是NetSingleBeanListener的子类,那么得到的父类是NetSingleBeanListener,他是带泛型的,可以通过代码取出泛型的类型,再反射
如果传入的aClass是SyncNetSingleBeanListener类,那么得到的父类是SyncNetHandleListener,他是不带泛型的,通过代码取出泛型时就会出错
那既然出现了问题,有办法能解决吗?总不能让同步请求实现不了吧。
一开始,我想到的是,不用getGenericSuperclass的方式取出泛型,而直接在aClass类中取出泛型,但是查阅相关资料后,发现这不可能的。
因为Java泛型去参数化(擦拭法)的原因,只有在
超类(调用 getGenericSuperclass 方法)
或者成员变量(调用 getGenericType 方法)
或者方法(调用 getGenericParameterTypes 方法)
像这些有方法返回 ParameterizedType 类型的时候才能反射成功
所以使用的时候,必须使用他的子类,而不能直接使用本类。
可以说这非常蛋疼,但你又不得不遵守这样的规则。
那还有其它办法可以解决这个问题吗?显然是有的,只要学习异步请求,用子类就行了。
笔者一开始是直接继承SyncNetSingleBeanListener来实现一个类,假设为MyListener吧,类里面是空的。然后传参的时候,new MyListener(),发现不行的,单步调试时发现aClass.getGenericSuperclass时,居然还是SyncNetHandleListener,没有深入去研究,笔者猜想是编译器直接把这个空的MyListener类给删除掉了。
于是为了让开发者使用框架的时候不混乱,知道要使用哪个Listener,我想到了另一种办法。
还是学异步请求,直接把SyncNetSingleBeanListener定义为抽象类
这样一来,在使用他的时候,不能直接new,因为抽象类不能生成对象,必须使用他的子类才可以,不然不能编译通过。
一般开发者可以用内部类的方式,其实也是用到了他的子类
使用内部类时,只要加一对花括号{}就可以了,因为里面没有未实现的抽象方法,所以花括号里面是空的。
同样,对于SyncNetListBeanListener,我们也定义为抽象类
在使用时也很简单
到这里,框架内的同步请求代码已经全部完成。
最后再来回忆一下第6篇的内容,讲的是自定义解析器,其实现方案也只能适合异步请求,那么在同步请求时,我们只要学着SyncNetSingleBeanListener的实现思路,进行一些修改就行
使用起来是这样的
使用的时候,因为监听器内部的实现,要使到具体数据的话,要从NetRetBean的serverObjectMap里面取,map的key的值根据SyncNetCustomBeanListener中定义的一样。
总结一下,
当所使用的Listener需要调用NetBaseBeanUtil时,就要实现成抽象类,在使用这类监听器时,要使用他的子类。此处的例子有SyncNetSingleBeanListener,SyncNetListBeanListener,SyncNetCustomBeanListener。
当所使用的Listener不需要调用NetBaseBeanUtil时,就不要实现成抽象类了,在使用这类监听器时,直接创建他的对象。此处的唯一例子就是SyncNetStringListener。
可以说在开发者的角度,使用本框架进行异步请求或者同步请求差别并不大,只是入口从get变成getSync,post变成postSync,监听器也换成了相应的就行了。还要注意的是在自定义监听器时,如果开发者有需要使用到同步请求,也要实现一个同步请求的自定义解析器。如果不需要,就不要实现了。
至此,同步请求的所有内容都已讲解完成。
下一篇将讲解对第三方解析框架的支持
Android通用网络请求解析框架.9(支持第三方解析框架)
开源库github地址 https://github.com/qq296216078/Android-Universial-NetFrame
如果有兴趣一起讨论本框架的内容,请加QQ群:271335749
上一篇中我们已经完成了同步请求公共部分的代码实现,核心监听器的代码是这样的
abstract public class SyncNetHandleListener implements SyncNetListener { 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); } abstract protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException; }
使用上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(); }
还是存在代码执行顺序模糊的问题。还有内层数据的解析,需要开发者自己来完成。
如果在onReceivedRet回调的解析方法中直接返回null,那么在返回的NetRetBean的内层数据还是为null。
为了不让使用者来实现内层数据的解析,所以就应该在框架内部实现内层数据的解析。
那应该怎样在框架内部进行解析呢?学异步请求就好了,继承SyncNetHandleListener,来看看子类中是怎样解析数据的
package com.chenjian.net.listener.sync; import com.chenjian.net.bean.NetRetBean; import org.json.JSONException; /** * 返回字String的网络请求Listener * <p> * 作者: ChenJian * 时间: 2016.12.15 14:54 */ public class SyncNetStringListener extends SyncNetHandleListener { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { netRetBean.setServerObject(netRetBean.getServerData()); return handleResult(netRetBean); } }
这里的handleResult是父类的方法,根据之前的代码,父类这个方法只是将NetRetBean原封不动的返回。
因为父类中定义抽象方法onReceivedRet时需要返回值,所以这里需要将内层数据进行解析,然后再返回。
还有一个变化,因为本类不存在抽象方法,所以本类也不是抽象类了,不要在类的前面加上abstract。
对比一下异步请求的代码实现
abstract public class NetStringListener extends NetHandleListener { @Override protected void onReceivedRet(NetRetBean netRetBean) throws JSONException { netRetBean.setServerObject(netRetBean.getServerData()); handleResult(netRetBean); } @SuppressWarnings("unchecked") @Override protected void onSuccess(CallbackCode successCode, NetRetBean netRetBean) { onSuccess((String) netRetBean.getServerObject()); } /** * 运行在ui线程,返回单个实体 * * @param string 当前string */ abstract protected void onSuccess(String string); }
可以看到,同步请求的时候,因为父类没有onSuccess方法,也不需要回调,所以同步请求代码实现起来更简单,只是将解析后的结果进行返回就可以了。
正如上面所说,同步请求的Listener不是抽象类,不要加abstract修饰类,
其它监听器也需要做类似的修改,继承SyncNetHandleListener,我们实现了SyncNetSingleBeanListener
package com.chenjian.net.listener.sync; import com.chenjian.net.bean.NetBaseBean; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.util.NetBaseBeanUtil; import org.json.JSONException; import org.json.JSONObject; /** * 返回是单个Bean的网络请求Listener * <p> * 作者: ChenJian * 时间: 2016.12.15 14:54 */ public class SyncNetSingleBeanListener<T extends NetBaseBean> extends SyncNetHandleListener { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { JSONObject object = new JSONObject(netRetBean.getServerData()); T t = NetBaseBeanUtil.parseItem(getClass(), 0, object); netRetBean.setServerObject(t); return handleResult(netRetBean); } }
再实现SyncNetListBeanListener
package com.chenjian.net.listener.sync; import com.chenjian.net.bean.NetBaseBean; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.util.NetBaseBeanUtil; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; /** * 返回是List<Bean>的网络请求Listener * <p> * 作者: ChenJian * 时间: 2016.12.15 14:54 */ public class SyncNetListBeanListener<T extends NetBaseBean> extends SyncNetHandleListener { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { JSONArray array = new JSONArray(netRetBean.getServerData()); List<T> list = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { JSONObject object = array.getJSONObject(i); T t = NetBaseBeanUtil.parseItem(getClass(), 0, object); list.add(t); } netRetBean.setServerObject(list); return handleResult(netRetBean); } }
可以看到,同步请求分支部分的代码和异步请求时差不多,只是父类不一样,还有最后需要将结果进行返回,而不是回调。
到此,框架中同步请求的代码都已经添加完成,可以开始使用了
private void syncGetString() { new Thread() { @Override public void run() { String originalString = NetHelper.getStringSync("url"); System.out.println(originalString); NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetStringListener()); 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(); }
getStringSync返回的是最原始的数据,没有经过解析的,他不需要传入监听器参数。
getSync返回的是NetRetBean,传入的监听器类型的不同,NetRetBean中serverObject类型也会不同。当然这里需要开发者自己取出来进行强转。
笔者一开始想把serverObject对象的类型变成泛型,后来发现如果是自定义监听器进行同步请求时,一个泛型对象不够通用,还是得用到serverObjectMap属性才行。
回顾上一篇中的需求,根据url1请求的结果判断是否请求url2,我们可以这样实现
private void syncGetString() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url1", new SyncNetStringListener()); if (netRetBean.isSuccess()) { NetHelper.getSync("url2", new SyncNetStringListener()); } try { Thread.sleep(60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }
这样的话,代码的执行顺序就很清晰了,返回值的方式也非常符合同步请求的需求,代码看起来简单明了。
我们接着再来使用其它的Listener来完成同步请求。
假设服务端返回的数据是这样的:
{ "code":"00001", "message":"login success", "time":"1479807260", "data":{ "id":"123", "name":"chenjian" } }
NetUserBean的代码与之前的一样,没有改变
public class NetUserBean extends NetBaseBean { private String id; private String name; @Override public void initByJson(JSONObject jsonObject) throws JSONException { this.id = jsonObject.optString("id"); this.name = jsonObject.optString("name"); } }
开始使用
private void syncGetBean() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetSingleBeanListener<NetUserBean>()); CallbackCode callbackCode = netRetBean.getCallbackCode(); switch (callbackCode) { case CODE_SUCCESS_REQUEST: NetUserBean userBean = (NetUserBean) netRetBean.getServerObject(); System.out.println(userBean.toString()); break; default: System.out.println(netRetBean.toString()); break; } } }.start(); }
居然报错了
NetRetBean{ mCallbackCode=CODE_ERROR_UNKNOWN, mException=java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType, mServerCode='null', mServerMsg='null', mServerTime='null', mServerData='null', mServerObject=null, mServerObjectMap=null}
再细看异常信息
01-11 13:35:45.470 2432-3428/com.chenjian.net W/System.err: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.util.NetBaseBeanUtil.getBean(NetBaseBeanUtil.java:41) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.util.NetBaseBeanUtil.parseItem(NetBaseBeanUtil.java:28) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.listener.sync.SyncNetSingleBeanListener.onReceivedRet(SyncNetSingleBeanListener.java:30) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.listener.sync.SyncNetHandleListener.sendSuccess(SyncNetHandleListener.java:46) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.core.sync.SyncNetExcutor.startRequest(SyncNetExcutor.java:83) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.core.sync.SyncNetExcutor.get(SyncNetExcutor.java:64) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.helper.NetHelper.getSync(NetHelper.java:96) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.helper.NetHelper.getSync(NetHelper.java:80) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.demo.activity.GetActivity$5.run(GetActivity.java:189) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.util.NetBaseBeanUtil.getBean(NetBaseBeanUtil.java:41) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.util.NetBaseBeanUtil.parseItem(NetBaseBeanUtil.java:28) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.listener.sync.SyncNetSingleBeanListener.onReceivedRet(SyncNetSingleBeanListener.java:30) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.listener.sync.SyncNetHandleListener.sendSuccess(SyncNetHandleListener.java:46) 01-11 13:35:45.471 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.core.sync.SyncNetExcutor.startRequest(SyncNetExcutor.java:83) 01-11 13:35:45.472 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.core.sync.SyncNetExcutor.get(SyncNetExcutor.java:64) 01-11 13:35:45.472 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.helper.NetHelper.getSync(NetHelper.java:96) 01-11 13:35:45.472 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.helper.NetHelper.getSync(NetHelper.java:80) 01-11 13:35:45.472 2432-3428/com.chenjian.net W/System.err: at com.chenjian.net.demo.activity.GetActivity$5.run(GetActivity.java:189)
重点在于这两行
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType at com.chenjian.net.util.NetBaseBeanUtil.getBean(NetBaseBeanUtil.java:41)
我们再看看NetBaseBeanUtil的41行代码
Class<T> entityClass = (Class<T>) ((ParameterizedType) aClass.getGenericSuperclass()).getActualTypeArguments()[tIndex];
很明显的看出来了,aClass.getGenericSuperclass后,是一个Object类型,不能强转为ParameterizedType。
可是之前的SyncNetStringListener为什么没有报错呢?因为SyncNetStringListener并没有用到NetBaseBeanUtil,只是将数据解析为String类型,而不需要使用到NetBaseBeanUtil方法来获取Bean。
那又为什么异步请求时都没问题,而在这个地方就有问题呢?
回忆一下第4篇中提到的java泛型去参数化的概念,我们再来看看NetBaseBeanUtil的代码
public class NetBaseBeanUtil { /** * @param aClass 带泛型 T 的类,应该传入xxBeanListener监听器或其的子类。他的父类必须是带泛型T的 * @param tIndex 泛型 T 所在下标 * @param jsonObject 用来解析的 json * @param <T> 泛型 T * @return 返回泛型T的实例 * @throws JSONException */ public static <T extends NetBaseBean> T parseItem(Class aClass, int tIndex, JSONObject jsonObject) throws JSONException { T t = getBean(aClass, tIndex); t.initByJson(jsonObject); return t; } /** * @param aClass 带泛型 T 的类,应该传入xxBeanListener监听器或其的子类。他的父类必须是带泛型T的 * @param tIndex 泛型 T 所在下标 * @param <T> 泛型 T * @return 返回泛型T的实例 */ @SuppressWarnings("unchecked") private static <T extends NetBaseBean> T getBean(Class aClass, int tIndex) { Class<T> entityClass = (Class<T>) ((ParameterizedType) aClass.getGenericSuperclass()).getActualTypeArguments()[tIndex]; T entity = null; try { // 使用newInstance创建实例的类,必须有无参构造方法 entity = entityClass.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return entity; } }
正如注释所说,这里的aClass的父类必须是带泛型的,而在使用异步请求的时候,因为需要回调,通常的做法是new一个Listener为内部类。而内部类实际上编译器会先定义一个类继承于他,然后再将那个类传入当参数。而同步请求,而直接new一个对象出来,并没有使用他的子类。一起来通过代码对比一下
异步请求我们使用内部类,其实get方法的第二个参数的类型,是NetSingleBeanListener的子类
NetHelper.get("url", new NetSingleBeanListener<NetUserBean>() { @Override protected void onError(CallbackCode errorCode, NetRetBean netRetBean) { } @Override protected void onSuccess(NetUserBean userBean) { } });
同步请求时,我们直接生成一个SyncNetStringListener的对象
NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetSingleBeanListener<NetUserBean>());
在两个Listener中,我们在使用NetBaseBeanUtil时,都调用了下面这一行代码
T t = NetBaseBeanUtil.parseItem(getClass(), 0, object);
getClass()非常重要,
在NetSingleBeanListener中,如果是他的子类调用了这个方法,那么返回的是他的子类
在SyncNetSingleBeanListener中,只是本类调用了这个方法,所以返回的是这个类本身
而这个时候,在NetBaseBeanUtil的getBean方法中,需要用到aClass.getGenericSuperclass,对传入的class对象进行操作,
如果传入的aClass是NetSingleBeanListener的子类,那么得到的父类是NetSingleBeanListener,他是带泛型的,可以通过代码取出泛型的类型,再反射
如果传入的aClass是SyncNetSingleBeanListener类,那么得到的父类是SyncNetHandleListener,他是不带泛型的,通过代码取出泛型时就会出错
那既然出现了问题,有办法能解决吗?总不能让同步请求实现不了吧。
一开始,我想到的是,不用getGenericSuperclass的方式取出泛型,而直接在aClass类中取出泛型,但是查阅相关资料后,发现这不可能的。
因为Java泛型去参数化(擦拭法)的原因,只有在
超类(调用 getGenericSuperclass 方法)
或者成员变量(调用 getGenericType 方法)
或者方法(调用 getGenericParameterTypes 方法)
像这些有方法返回 ParameterizedType 类型的时候才能反射成功
所以使用的时候,必须使用他的子类,而不能直接使用本类。
可以说这非常蛋疼,但你又不得不遵守这样的规则。
那还有其它办法可以解决这个问题吗?显然是有的,只要学习异步请求,用子类就行了。
笔者一开始是直接继承SyncNetSingleBeanListener来实现一个类,假设为MyListener吧,类里面是空的。然后传参的时候,new MyListener(),发现不行的,单步调试时发现aClass.getGenericSuperclass时,居然还是SyncNetHandleListener,没有深入去研究,笔者猜想是编译器直接把这个空的MyListener类给删除掉了。
于是为了让开发者使用框架的时候不混乱,知道要使用哪个Listener,我想到了另一种办法。
还是学异步请求,直接把SyncNetSingleBeanListener定义为抽象类
package com.chenjian.net.listener.sync; import com.chenjian.net.bean.NetBaseBean; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.util.NetBaseBeanUtil; import org.json.JSONException; import org.json.JSONObject; /** * 返回是单个Bean的网络请求Listener * <p> * 由于去参数化(擦拭法),也只有在 * 超类(调用 getGenericSuperclass 方法) * 或者成员变量(调用 getGenericType 方法) * 或者方法(调用 getGenericParameterTypes 方法) * 像这些有方法返回 ParameterizedType 类型的时候才能反射成功 * <p> * 所以使用的时候,必须使用他的子类,而不能直接使用本类 * <p> * 作者: ChenJian * 时间: 2016.12.15 14:54 */ abstract public class SyncNetSingleBeanListener<T extends NetBaseBean> extends SyncNetHandleListener { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { JSONObject object = new JSONObject(netRetBean.getServerData()); T t = NetBaseBeanUtil.parseItem(getClass(), 0, object); netRetBean.setServerObject(t); return handleResult(netRetBean); } }
这样一来,在使用他的时候,不能直接new,因为抽象类不能生成对象,必须使用他的子类才可以,不然不能编译通过。
一般开发者可以用内部类的方式,其实也是用到了他的子类
private void syncGetBean() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetSingleBeanListener<NetUserBean>() { }); CallbackCode callbackCode = netRetBean.getCallbackCode(); switch (callbackCode) { case CODE_SUCCESS_REQUEST: NetUserBean userBean = (NetUserBean) netRetBean.getServerObject(); System.out.println(userBean.toString()); break; default: System.out.println(netRetBean.toString()); break; } } }.start(); }
使用内部类时,只要加一对花括号{}就可以了,因为里面没有未实现的抽象方法,所以花括号里面是空的。
同样,对于SyncNetListBeanListener,我们也定义为抽象类
package com.chenjian.net.listener.sync; import com.chenjian.net.bean.NetBaseBean; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.util.NetBaseBeanUtil; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; /** * 返回是List<Bean>的网络请求Listener * <p> * 由于去参数化(擦拭法),也只有在 * 超类(调用 getGenericSuperclass 方法) * 或者成员变量(调用 getGenericType 方法) * 或者方法(调用 getGenericParameterTypes 方法) * 像这些有方法返回 ParameterizedType 类型的时候才能反射成功 * <p> * 所以使用的时候,必须使用他的子类,而不能直接使用本类 * <p> * 作者: ChenJian * 时间: 2016.12.15 14:54 */ abstract public class SyncNetListBeanListener<T extends NetBaseBean> extends SyncNetHandleListener { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { JSONArray array = new JSONArray(netRetBean.getServerData()); List<T> list = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { JSONObject object = array.getJSONObject(i); T t = NetBaseBeanUtil.parseItem(getClass(), 0, object); list.add(t); } netRetBean.setServerObject(list); return handleResult(netRetBean); } }
在使用时也很简单
private void syncGetListBean() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.getSync("url", new SyncNetListBeanListener<NetUserBean>() { }); CallbackCode callbackCode = netRetBean.getCallbackCode(); switch (callbackCode) { case CODE_SUCCESS_REQUEST: List<NetUserBean> userBeen = (List<NetUserBean>) netRetBean.getServerObject(); for (int i = 0; i < userBeen.size(); i++) { System.out.println(userBeen.get(i).toString()); } break; default: System.out.println(netRetBean.toString()); break; } } }.start(); }
到这里,框架内的同步请求代码已经全部完成。
最后再来回忆一下第6篇的内容,讲的是自定义解析器,其实现方案也只能适合异步请求,那么在同步请求时,我们只要学着SyncNetSingleBeanListener的实现思路,进行一些修改就行
package com.chenjian.net.demo.listener.sync; import com.chenjian.net.bean.NetBaseBean; import com.chenjian.net.bean.NetRetBean; import com.chenjian.net.listener.sync.SyncNetHandleListener; import com.chenjian.net.util.NetBaseBeanUtil; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 作者: ChenJian * 时间: 2016.12.16 13:51 */ abstract public class SyncNetCustomBeanListener<Page extends NetBaseBean, T extends NetBaseBean> extends SyncNetHandleListener { @Override protected NetRetBean onReceivedRet(NetRetBean netRetBean) throws JSONException { JSONObject jsonObject = new JSONObject(netRetBean.getServerData()); Page page = NetBaseBeanUtil.parseItem(getClass(), 0, jsonObject); List<T> list = new ArrayList<>(); JSONArray jsonArray = jsonObject.getJSONArray("list"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject object = jsonArray.getJSONObject(i); T t = NetBaseBeanUtil.parseItem(getClass(), 1, object); list.add(t); } Map<String, Object> map = new HashMap<>(); map.put("page", page); map.put("list", list); netRetBean.setServerObjectMap(map); return handleResult(netRetBean); } }
使用起来是这样的
private void syncCustom() { new Thread() { @Override public void run() { NetRetBean netRetBean = NetHelper.postSync("url", "param", new SyncNetCustomBeanListener<NetPageBean, NetInfoBean>() { }); CallbackCode callbackCode = netRetBean.getCallbackCode(); switch (callbackCode) { case CODE_SUCCESS_REQUEST: Map<String, Object> map = netRetBean.getServerObjectMap(); NetPageBean pageBean = (NetPageBean) map.get("page"); List<NetInfoBean> infoBeen = (List<NetInfoBean>) map.get("list"); System.out.println(pageBean.toString()); for (int i = 0; i < infoBeen.size(); i++) { System.out.println(infoBeen.get(i).toString()); } break; default: System.out.println(netRetBean.toString()); break; } } }.start(); }
使用的时候,因为监听器内部的实现,要使到具体数据的话,要从NetRetBean的serverObjectMap里面取,map的key的值根据SyncNetCustomBeanListener中定义的一样。
总结一下,
当所使用的Listener需要调用NetBaseBeanUtil时,就要实现成抽象类,在使用这类监听器时,要使用他的子类。此处的例子有SyncNetSingleBeanListener,SyncNetListBeanListener,SyncNetCustomBeanListener。
当所使用的Listener不需要调用NetBaseBeanUtil时,就不要实现成抽象类了,在使用这类监听器时,直接创建他的对象。此处的唯一例子就是SyncNetStringListener。
可以说在开发者的角度,使用本框架进行异步请求或者同步请求差别并不大,只是入口从get变成getSync,post变成postSync,监听器也换成了相应的就行了。还要注意的是在自定义监听器时,如果开发者有需要使用到同步请求,也要实现一个同步请求的自定义解析器。如果不需要,就不要实现了。
至此,同步请求的所有内容都已讲解完成。
下一篇将讲解对第三方解析框架的支持
Android通用网络请求解析框架.9(支持第三方解析框架)
相关文章推荐
- Android通用网络请求解析框架.7(同步请求,公共部分)
- Android通用网络请求解析框架.4(代码实现,分支部分)
- Android通用网络请求解析框架.3(代码实现,公共部分)
- 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中