之所以写这篇文章是最近我们自己的项目打算实现mvp模式的功能重构,而我们的项目数据接口全部是基于webservices接口实现的,查阅了下资料发现Rxjava+retrofit的框架不是一般的火,内心不免躁动起来,经过一天半的时间总结摸索出一个登陆的demo。整体框架是RXjava+retrofit+okhttp 的mvp模式。废话不少了开始吧
开始之前就是小白一枚,准备工作如下:
1、什么是mvp
3、应该放在最后的之前写的demo(包括单纯webservices访问;mvp模式的练习;rxjava练习)
先看看框架的样子,上图,包名对应的意思简单解释下
api:和明显了在里边放了一个登录用的接口
convert:很重要,自定义的Retrofit convert,主要作用是自定义retrofit发送和接收的数据格式,特别是当前要发送的数据是xml格式,而我们返回的数据又要求截取其中的json要求
ksoap2,kxml2:这两个包存储了从ksoap的源码中copy过来的源码,目的是借用其中拼接xm,和请求头的实现
model:模型
presenter:主要的逻辑代码,控制view的显示
view:也就是activity了
曰:授人以鱼不如授人以渔
文章想从自己的问题解决思路出发,讲讲如何是实现webservices访问的,首先不得不说一下我们之前抛弃所有的框架、思路仅仅借助ksoap2的jar包是如何实现webservices访问的(相信看这篇文章的同学都是对webservices访问有所了解的人,真是不明白的请自行度娘):
webservices是如何发送请求的
通过soapUI工具我们可以很清楚的看到,其本质就是将参数组装在一个xml格式的数据中发送,发送和结果接收均是以xml的格式存在的,看看通过soapUI请求的格式就明白了:
ksoap2实现访问webservices
看下访问的关键代码:
41-46将参数通过map的方式传入
48-54查看源码也就是组装xml和请求头的过程
56-64调用http的请求,发送接口请求
65-66获取请求结果,当然查看源码我们知道这个地方对返回的结果(原始的访问返回为xml格式的)进行的解析
因为我们自己的接口返回的数据格式都是严格的json,所以最后的返回数据处理还包括
SoapObject resultsRequestSOAP = (SoapObject)envelope.bodyIn;
Object obj = resultsRequestSOAP.getProperty(0);
String jsonStr = obj.toString();
来获取json字符串
通过以上,就很明白了要想实现webservices的访问无非就是(1)想办法组装xml(2)如何将返回xml中的json数据提取出来,结合我们现在要整合RXjava+retrofit+okhttp那么我们还需要考虑(自定义的convert)
RXjava-----mvp
1.添加需要依赖的库
compile'com.squareup.retrofit2:retrofit:2.1.0'
compile'com.squareup.okhttp3:okhttp:3.4.2'
compilegroup:'com.squareup.okhttp3',name:'okhttp-urlconnection',version:'3.3.0'
compile'com.squareup.retrofit2:converter-gson:2.1.0'
//适配器
compile'com.squareup.retrofit2:adapter-rxjava:2.1.0'
//RxJava
compile'io.reactivex:rxjava:1.1.6'
//RxAndroid
compile'io.reactivex:rxandroid:1.2.1'
//用来自定义的转换器(关键词:retrofit请求字符串,非json)
compile'com.squareup.retrofit2:converter-gson:2.1.0'
2、建立各个包,就像我在开头贴出来的样子,主要是为了mvp模式的调理准备的
3、采用ksoap中的源码,我们不使用ksoap中网络访问的代码,这部分代码请自行裁剪,只保留其中的组拼装xml部分。
我们在使用ksoap2的方法中,最后的数据调用使用的是HttpTransportSE.call(“”,enveloap),找到代码中call方法,我们可以看到其中组装xml的代码
call方法的代码量还时挺大的这里为了避免篇幅过长(已经很长了),就不在张贴,我们通过看其中的call方法我们发现
(1)包括了http的请求头 beader
(2)包括了使用byte[] requestData = createRequestData(envelope,"UTF-8");将envelope转成xml
(3)建立http的链接并发起请求
偶然发现一个地方,call方法在设置http请求的时候设置了connection.setRequestMethod("POST");post的请求方法,妈妈再也不用担心我在定义api接口的时候纠结使用get还是post了。当然就算没发现post也应该有意识明白使用post才对
4、翻过头来继续看看我们的目录结构
创建api接口
public interfaceILoginApi {
@POST("/services/loginService")
rx.ObservableloginForMobile(@HeaderMapMap headerMap,@BodyString body);
}
毅然决然的使用了post,设置好url(请求的url都是拼接的,这个地方直接写除baseurl以外的部分就可以了),登录接口定义的参数需要设置请求的header,和请求的字符串(这里是组装后的xml)
创建model
因为我们接口返回的数据统一json格式必包含{“message”:"","statuscode":200},所以创建一个基类BaseEnty作为其他实体的父类
public abstract classbaseEntity {
privateStringmessage;
privateStringstatuscode;
publicStringgetStatuscode() {returnstatuscode;}
public voidsetStatuscode(Stringstatuscode) {this.statuscode= statuscode;}
publicStringgetMessage() {returnmessage;}
public voidsetMessage(Stringmessage) {this.message= message;}
}
prestener接口
定义的很简单就是在主页面显示登录后返回的信息
public interfaceILoginPresenter {
voidlogin(Stringusername,Stringpwd);
}
view页面省去不写
这里描述下presenter的实现
soapHelpers是一个单例,里边包含了传输参数后返回xml请求body和请求header的方法
至此调用api的方法就本应该可以实现网路的访问了
loginApi.loginForMobile(soapHeaderMap,mBody)
.subscribeOn(Schedulers.io())
//指定回调在哪执行
.observeOn(AndroidSchedulers.mainThread())
.subscribe(newAction1() {
@Override
public voidcall(User responseBody) {
String respone = responseBody.getMessage();
Log.v(TAG,"respone:"+ respone);
iLoginView.displayLoginMessage(respone);
}
}, newAction1() {
@Override
public voidcall(Throwable throwable) {
Log.v(TAG,"error:"+ throwable.toString());
}
});
细心的同学会发现,如果直接使用的是addConverterFactory(GsonConverterFactory.create())转换器,那么一个问题是我们如何才能将返回的数据按照我们想要的格式返回呢??我们定义的api接口中返回的user对象怎么样才能生效呢,我么返回的数据可是赤裸裸的xml啊!我们可什么也没做呢。。。。。。细思极恐,抓紧查了下自定义retrofit 的convert,然后我们将自定义的转换conver实现
数据的request按照教程直接写就ok,思想就是保证我们的retrofit能够发送自定义的字符串(也就是xml),重点是解析返回数据,得到我们想要的json
想到这里呦呦呦去看了一眼soap的源码
SoapObject resultsRequestSOAP = (SoapObject)envelope.bodyIn;
Object obj = resultsRequestSOAP.getProperty(0);
String jsonStr = obj.toString();
最后将我们自定义的转换器配置到retrofit中SoapConverterFactory.create()
retrofit=newRetrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(SoapConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
运行ok
没有忘记上源码:https://github.com/sunfengqi8023/LoginForSoapAndRxjava
#### 欢迎访问我的CSDN [熊猫卓Sun博客](http://blog.csdn.net/sfq19881224)