最近一段时间简单的应用了一下rxjava 和 retrofit,废话不多说直接写我实践的过程和大家分享,希望和大家切磋,有不对的希望大家批评指正。
前提:对rxjava和retrofit有一个简单的基本了解,RxJava可以参考http://gank.io/post/560e15be2dca930e00da1083#toc_3
Retrofit 可以参考http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0915/3460.html,http://blog.csdn.net/duanyy1990/article/details/52139294。
在此只是提供了一些当时我初次接触时候学习的资料,我的实践前提是:
(1)通过post请求传递json数据给服务器--------post请求,bean转为json
(2)在传递之前需要将json数据进行加密--------自定义转换器converter,将json加密
(3)对请求数据统一添加请求头,解析响应头------通过拦截器
(4)服务器返回的数据进行解密成json数据--------自定义转换器converter,将数据解密成json串
(5)返回的json数据转为对应的bean对象进行操作-----json转为bean进行操作
下面粘贴处我的部分代码,以初始化代码为例:
(一)bean转json
1.1初始化 实体类:
public class InitEntity extends BaseEntity { private String channelCode;//渠道号 private String isFirstInstall;//01是,02不是 private String publicKeyVersion;//服务器公钥版本号 private String publicKey;//服务器公钥 private String updateFlag;//更新标识 private String downUrl;//下载地址 private String updateDesc;//更新内容 public String getChannelCode() { return channelCode; } public void setChannelCode(String channelCode) { this.channelCode = channelCode; } public String getIsFirstInstall() { return isFirstInstall; } public void setIsFirstInstall(String isFirstInstall) { this.isFirstInstall = isFirstInstall; } public String getPublicKeyVersion() { return publicKeyVersion; } public void setPublicKeyVersion(String publicKeyVersion) { this.publicKeyVersion = publicKeyVersion; } public String getPublicKey() { return publicKey; } public void setPublicKey(String publicKey) { this.publicKey = publicKey; } public String getUpdateFlag() { return updateFlag; } public void setUpdateFlag(String updateFlag) { this.updateFlag = updateFlag; } public String getDownUrl() { return downUrl; } public void setDownUrl(String downUrl) { this.downUrl = downUrl; } public String getUpdateDesc() { return updateDesc; } public void setUpdateDesc(String updateDesc) { this.updateDesc = updateDesc; } }1.2 对应retrofit 请求接口:
public interface InitApi { @POST("user/init.action") Observable<BaseResponseEntity> getInit(@Body InitEntity initEntity); }1.3 具体的接口请求:
(这是我自己封装的一个简单的请求类的部分重要代码)
mRetrofit = new Retrofit.Builder() .baseUrl(BaseApplication.Server_Url) .addConverterFactory(JsonConverterFactory.create())//添加自定义转换器) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(genericClient()) .build();下面的是主要的请求过程
InitApi initApi = HttpUtils.getInstance().create(InitApi.class); initApi.getInit(initEntity) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(mSubscriber);
(二) 自定义转换器,这个很重要,我传递的是bean对象,需要自定义转换器里面对其转换成json数据,然后进行加密,加密之后传递给服务器
public class JsonRequestBodyConverter<T> implements Converter<T, RequestBody> { private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); private final Gson gson; private final TypeAdapter<T> adapter; /** * 构造器 */ public JsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) { this.gson = gson; this.adapter = adapter; } @Override public RequestBody convert(T value) throws IOException { //将bean转为json数据,对json数据加密成字符串类型后传递给后台 String data = gson.toJson(value); String encryData = EncryptUtils.getInstance().encryptJson(data); return RequestBody.create(MEDIA_TYPE, encryData); } }(三) 添加请求头header 拦截器
public Interceptor generateInterceptor() { Interceptor interceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); request.newBuilder().cacheControl(CacheControl.FORCE_CACHE); //header和 addHeader区别在于header如果有key重复的话是会被覆盖的,而addHeader()允许相同key值的header存在 if (CcFormatStr.isNotNull(mApplication.getSessionId())) { request.newBuilder().header("Cookie", "JSESSIONID=" + mApplication.getSessionId()); if (CcFormatStr.isNotNull(mApplication.getUserToken())) { request.newBuilder().header("Cookie", "JSESSIONID=" + mApplication.getSessionId()) .header("userToken", mApplication.getUserToken()); } } Response response = chain.proceed(request); if (response.isSuccessful()) { String value = response.header("Set-Cookie"); if (CcFormatStr.isNotNull(value)) { int b = value.indexOf("JSESSIONID=");//JSESSIONID=854E6696D8D4DF9A94E09CCF7C0E92D0; Path=/; HttpOnly if (b > -1) { int c = value.indexOf(";"); String sessionID = value.substring(b + 11, c); mApplication.setSessionId(sessionID); } } if (CcFormatStr.isNotNull(response.header("userToken"))) { mApplication.setUserToken(response.header("userToken")); } } return response; } }; return interceptor; }(四)解密数据,服务器返回的是一个string串,解密后成3段,分别是响应码,响应数据,说明原因
public class JsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final Gson mGson;//gson对象 private final TypeAdapter<T> adapter; /** * 构造器 */ public JsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) { this.mGson = gson; this.adapter = adapter; } /** * 转换 * * @param responseBody * @return * @throws IOException */ @Override public T convert(ResponseBody responseBody) throws IOException { String response = responseBody.string(); //解密 String result[] = EncryptUtils.getInstance().deCodeJson(response); //返回的3段报文:是否成功,响应数据,失败和成功的说明 BaseResponseEntity entity = new BaseResponseEntity(); entity.setIsSuccess(result[0]); entity.setResultResponse(result[1]); entity.setResultMsg(result[2]); return (T) entity; } }(四)请求成功:这里的ResponseObserver是继承了Subscriber<BaseResponseEntity>,对成功,失败,完成等方法进行了二次封装
Subscriber mSubscriber = new ResponseObserver(this) { @Override public void onError(Throwable e) { String msg = ""; if (e instanceof HttpException || e instanceof IOException) { msg ="网络连接异常"; } else if (e instanceof ApiException) { msg = ((ApiException) e).getErrorMsg(); } else { Log.e(TAG, e.getMessage()); } CcAlertUtils.showWarnDialog(mActivity, msg, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); } @Override public void onSuccess(String response) { InitEntity initEntity = JsonUtils.resolveEntity(response, InitEntity.class); if (ApiCode.HTTP_SUCCESS.equals(initEntity.getRespCode())) { if (CcFormatStr.isNotNull(initEntity.getPublicKey())) { CcSharedPreUtils.getInstance(mActivity).saveKeyObjValue(CcSharedPreUtils.PUBLIC_KEY, initEntity.getPublicKey()); } if (CcFormatStr.isNotNull(initEntity.getPublicKeyVersion())) { CcSharedPreUtils.getInstance(mActivity).saveKeyObjValue(CcSharedPreUtils.PUBLIC_KEY_VERSION, initEntity.getPublicKeyVersion()); } /*if(CcFormatStr.isNotNull(mApplication.getUserToken())){ CcSharedPreUtils.getInstance(mActivity).saveKeyObjValue(CcSharedPreUtils.USER_TOKEN, mApplication.getUserToken()); }*/ goMainActivity(); } else { if (CcFormatStr.isNotNull(initEntity.getPublicKey())) { CcSharedPreUtils.getInstance(mActivity).saveKeyObjValue(CcSharedPreUtils.PUBLIC_KEY, initEntity.getPublicKey()); } if (CcFormatStr.isNotNull(initEntity.getPublicKeyVersion())) { CcSharedPreUtils.getInstance(mActivity).saveKeyObjValue(CcSharedPreUtils.PUBLIC_KEY_VERSION, initEntity.getPublicKeyVersion()); } goMainActivity(); } } };
大体上一个简单的网络请求过程就是这样了post+body+转换器+加解密
遇到的问题:1,传递加密的json数据---body+自定义的json转换器解决了我需要对json加密后传输的问题,也就是bean转字符串的一个过程
2.在这个项目中还有一个问题是当网络请求结合上拉加载与下拉刷新的问题(需要重复请求同一个url),subscriber 需要每次都new出来一个新的!
项目中用到的技术点:
1.recyclerview+swiperefreshlayout+自定义上拉加载
2.listview+swiperefreshlayout+自定义上拉加载
3.listview的item的滑动删除
4.retrofit+rxjava简单封装的网络请求
5.TabHost+Fragment底部菜单栏
6TabLayout+Viewpager的滑动导航栏
7导航栏里面嵌套3fragment----2个listview和1个viewpager(无限循环和定时循环)为了多层嵌套测试放的
8 glide 加载网络图片
下面是我的demo,注意:这里的retrofit没有用到加密,所以demo和上述可能有点出入,demo中额外加入了分享,有需要的可以下载,希望和大家交流!
下载地址 : https://github.com/wjn919/MyOpenRetorfit