android – 用于未知根元素的Retrofit和SimpleXML?

android – 用于未知根元素的Retrofit和SimpleXML?,第1张

概述我们目前正在为 XML API设置Retrofit – 不幸的是,每个请求都可以使用两个不同的根元素之一返回响应. 通常,每个响应都是这样的(当然,< response>标记中包含的实际元素随每个请求而变化): <?xml version="1.0" encoding="UTF-8"?><response> <SomeInfo>Some Info</SomeInfo> <More 我们目前正在为 XML API设置Retrofit – 不幸的是,每个请求都可以使用两个不同的根元素之一返回响应.

通常,每个响应都是这样的(当然,< response>标记中包含的实际元素随每个请求而变化):

<?xml version="1.0" enCoding="UTF-8"?><response>    <SomeInfo>Some Info</SomeInfo>    <MoreInfo>More Info</MoreInfo></response>

每个错误都是这样的(这里的结构对于每个响应都是相同的):

<?xml version="1.0" enCoding="UTF-8"?><error>    <code>125002</code>    <message></message></error>

现在,到目前为止我们发现的唯一方法是以一种通用的方式完成这项工作,如下所示:

public interface API {    @GET("/API/sessionToken")    Observable<ResponseBody> requestSessionToken();    @GET("/API/pinStatus")    Observable<ResponseBody> requestPinStatus();}public class RestClIEnt {    public RestClIEnt() {        // ...        mAPIService = retrofit.create(API.class);    }    public Observable<PinStatusResponse> requestPinStatus() {        return mAPIService.requestPinStatus()                .flatMap(foo(PinStatusResponse.class,PinStatusResponseData.class));    }    public Observable<SessionTokenResponse> requestSessionToken() {        return mAPIService.requestSessionToken()                .flatMap(foo(SessionTokenResponse.class,SessionTokenResponseData.class));    }    private final <O extends MyResponse,I> Func1<ResponseBody,Observable<T>> foo(final Class<O> outerCls,final Class<I> innerCls) {        return new Func1<ResponseBody,Observable<O>>() {            @OverrIDe            public Observable<O> call(ResponseBody responseBody) {                try {                    final String xmlString = responseBody.string();                    final XmlPullParser parser = Xml.newPullParser();                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_nameSPACES,false);                    parser.setinput(new ByteArrayinputStream(xmlString.getBytes(Charset.forname("UTF-8"))),null);                    parser.nextTag();                    final String roottag = parser.getname();                    final Serializer serializer = new Persister();                    if (TextUtils.equals(roottag,"error")) {                        final MyError myError = serializer.read(MyError.class,xmlString);                        return Observable.just((O) outerCls.getConstructor(MyError.class,innerCls).newInstance(myError,null));                    } else if (TextUtils.equals(roottag,"response")) {                        final I data = serializer.read(innerCls,xmlString);                        return Observable.just((T) outerCls.getConstructor(MyError.class,innerCls).newInstance(null,data));                    }                } catch (XmlPullParserException e) {                    return Observable.error(e);                } catch (IOException e) {                    return Observable.error(e);                } catch (Exception e) {                    return Observable.error(e);                }                return Observable.error(new Exception("Should not be reached..."));            }        };    }​}

Response类看起来像这样:

public abstract class MyResponse<T> {    public final MyError error;    public final T data;    protected MyResponse(MyError error,T data) {        this.error = error;        this.data = data;    }}

和:

public final class PinStatusResponse extends MyResponse<PinStatusResponseData> {    public PinStatusResponse(MyError error,PinStatusResponseData data) {        super(error,data);    }}

并且所有* Data类都直接对应于(非错误)XML响应.

现在,我的问题是:有没有更简单的方法来解决这个问题? (如果是这样,这是不良API设计的标志吗?).

解决方法 这就是@ElementUnion注释的用途.您可以通过使用带注释的对象使用纯Retrofit SimpleXML API来解决这个问题:

@Rootpublic class ResponseBody {    public interface IAPIResponse {    }    @Root    public static class ValIDResponse implements IAPIResponse {        @Element(name="SomeInfo") String someInfo;        @Element(name="MoreInfo") String moreInfo;    }    @Root    public static class ErrorResponse implements IAPIResponse {        @Element(name="code") int code;        @Element(name="message") String message;    }    @ElementUnion({        @Element(name="response",type=ValIDResponse.class),@Element(name="error",type=ErrorResponse.class)    })    IAPIResponse APIResponse;}

*’ValIDResponse’和’ErrorReponse’的具体结构必须根据您拥有的真实XML结构进行更改.您可能还希望考虑在他们的@Root中添加’strict = false’.

至于你的’API’界面,它必须看起来像这样(注意我在使用Retrofit的Call类时):

public interface API {    @GET("/API/sessionToken")    Call<ResponseBody> requestSessionToken();    @GET("/API/pinStatus")    Call<ResponseBody> requestPinStatus();}

最后,调用本身(例如requestPinStatus())应该根据这个骨架实现来解决:

Call<ResponseBody> result = mAPIService.requestPinStatus();result.enqueue(new Callback<ResponseBody>() {    @OverrIDe    public voID onResponse(Response<ResponseBody> response,Retrofit retrofit) {        // ...        if (response.body().APIResponse instanceof ValIDResponse) {            // ...        } else if (response.body().APIResponse instanceof ErrorResponse) {            // ...        }    }    @OverrIDe    public voID onFailure(Throwable t) {        // ...    }});

有关ElementUnion和Simple-XML注释的更多信息,请参阅this guide.

总结

以上是内存溢出为你收集整理的android – 用于未知根元素的Retrofit和SimpleXML?全部内容,希望文章能够帮你解决android – 用于未知根元素的Retrofit和SimpleXML?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/1123657.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-30
下一篇 2022-05-30

发表评论

登录后才能评论

评论列表(0条)

保存