现在手上的项目后台返回的是XML字符串,用惯了JSON + GSON的我第一考虑的就是自动化解析,那么多接口,那么多属性,用DOM或者萨克斯解析太浪费时间了,而且扩展性也不好。网上的关于retrofit2 + simplexml的的文章真的非常少,可见XML是多么不受客户端欢迎,没办法,胳膊拧不过大腿,只能接受XML传输数据。
//网络
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'com.orhanobut:hawk:2.0.0-Alpha'
compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'
compile('com.squareup.retrofit2:converter-simplexml:2.0.0-beta4') {
exclude group: 'xpp3', module: 'xpp3'
exclude group: 'stax', module: 'stax-api'
exclude group: 'stax', module: 'stax'
}
这是的build.gradle里面的一部分。这个simplexml的的版本一定要跟上面的其他版本一模一样,不然就GG。
初始化retrofit2
public class Api {
private static ApiService SERVICE;
private static XmlApisService xmlApisService;
/**
* 请求超时时间
*/
private static final int DEFAULT_TIMEOUT = 8000;
public static XmlApisService getXml(final Context context){
if (xmlApisService == null) {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
/**
* 拦截器
*/
httpClientBuilder.addNetworkInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl.Builder authorizedUrlBuilder = request.url()
.newBuilder()
//添加统一参数 如手机唯一标识符,token等
.addQueryParameter("guid", AppTools.getIMEI(context))
.addQueryParameter("siteid", Constants.GAME_SITE_ID)
.addQueryParameter("unionid", Constants.GAME_UNIONID)
.addQueryParameter("version", AppTools.getVersionCode(context)+"")
.addQueryParameter("plat", Constants.GAME_PLAT);
Request newRequest = request.newBuilder()
//对所有请求添加请求头
// .header("mobileFlag", "adfsaeefe").addHeader("type", "4")
.method(request.method(), request.body())
.url(authorizedUrlBuilder.build())
.build();
if (chain!=null){
return chain.proceed(newRequest);
}
return null;
}
});
xmlApisService = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(SimpleXmlConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Url.BASE_URL)
.build().create(XmlApisService.class);
}
return xmlApisService;
}
}
辣么多代码,其实关键就是一句addConverterFactory(SimpleXmlConverterFactory.create())这一句。
举个例子服务器返回的XML是这样的
<?xml version="1.0" encoding="utf-8" ?>
<Results>
<Result Result="10000" message="" />
<Items>
<Item Src ="http://phonetest.91y.com/common/images/banner01.png" Remark="" JumpURL="http://m.91y.com/" Type="0"/>
<Item Src ="http://phonetest.91y.com/common/images/banner02.png" Remark="" JumpURL="http://m.91y.com/" Type="0"/>
<Item Src ="http://phonetest.91y.com/common/images/banner02.png" Remark="" JumpURL="http://m.91y.com/" Type="1"/>
</Items>
</Results>
package com.yxsq.fuyun.netbean.home;
import com.yxsq.fuyun.netbean.MessageResult;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
/ **
*由海峰于2017/5/27创建。
* ElementList:申明该元素是一个集合。
*元素:申明该元素只是一个普通属性
* inline = true:ElementList的一个属性,由于ElementList包了一层,如果为false将不能解析。
* required = false:实体类中有,xml中没有,且声明为@Element的,在@Element中加上required = false即可。
* @Root(strict = false):xml中有元素,而实体类中没有,在实体类的@(Root)中加上strict = false如@Root(strict = false)即可。
* http://blog.csdn.net/Picasso_L/article/details/53583507
* http://blog.csdn.net/qqyanjiang/article/details/51199111
* http://blog.csdn.net/qqyanjiang/article/details/51200108
* /
@Root(name =“Results”,strict = false)
public class HomeBannerResult {
@Element(name =“Result”)
public MessageResult codeMsg;
@Element(name =“Items”)
public HomeListBanner数据;
}
我相信你们看到我的注解和注释也就明白了,关键是不能用内部类,那是绝对绝对不行的。规规矩矩一个一个类来建。
package com.yxsq.fuyun.netbean;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Root;
/ ** *由海峰于2017/5/27创建。
* /@Root(name =“Result”,strict = false)
public class MessageResult
{
@Attribute(name =“Result”,required = false)
public String ResultCode;
@Attribute(name =“message”,required = false)
public String msg;
}
package com.yxsq.fuyun.netbean.home;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import java.util.List;
/ **
*由haifeng于2017/6/1创建。
* /
@Root(name =“Items”,strict = false)
public class HomeListBanner {
@ElementList(name =“Item”,inline = true,required = false)
public List <HomeBannerBean> data;
}
package com.yxsq.fuyun.netbean.home;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Root;
/ **
*由海峰于2017/5/27创建。
* /
@Root(name =“Item”,strict = false)
public class HomeBannerBean {
@attribute(name= “Src”)
public String src;
@attribute(name= “Remark”)
public String Remark;
@Attribute(name =“JumpURL”)
public String jumpUrl;
@Attribute(name =“Type”)
public String type;
}
类已经创建完了,注解也搞完了。比如后台突然加了一个字段,就在HomeBannerBean里面加入一个属性,
调用如下。
//首页banner区展示图片
@GET("do.aspx?action=getbannericon")
Observable<HomeBannerResult> getHomeBanner(@Query("sign") String sign);
/**
* 获取首页轮播图
*/
public Subscription getHomeBannerData() {
Subscription subscription = Api.getXml(mContext).getHomeBanner(QuaryMD5.getInstants().commendMd5(mContext)).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<HomeBannerResult>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
if (listener!=null){
listener.onError(Constants.GAME_NET_ERROR);
}
}
@Override
public void onNext(HomeBannerResult homeBannerResult) {
if (listener!=null) {
if ("10000".equals(homeBannerResult.codeMsg.ResultCode)) {
listener.onBannerRequested(homeBannerResult.data.data);
} else {
listener.onError(homeBannerResult.codeMsg.msg);
}
}
}
});
return subscription;
}
扫描头像,公众号来一波关注呗。