转换改装回调值以返回包络对象

Ant*_*opp 1 java android rx-java rx-android retrofit2

我的问题是关于使用RxJava for Android来处理来自Retrofit调用的数据的可能性.

我刚刚开始使用这些库,所以如果我的问题很简单,请耐心等待.

这是我的情景.

我有一个从服务器返回的json,看起来像这样

  { <--- ObjectResponse
     higher_level: {
        data: [
            {
               ...
               some fields,
               some inner object: {
               ....
                },
               other fields
            }, <----- obj 1

            ....,

            {
               ....
            }<---- obj n

         ]<-- array of SingleObjects

      }

  } <--- whole ObjectResponse
Run Code Online (Sandbox Code Playgroud)

我已经有改造得到这个响应并在ObjectResponse中解析.解析这个对象,我可以获得一个我可以像往常一样传递给我的RecyclerView适配器的List.

所以改造返回了ObjectResponse,它是整个服务器答案的模型,在改装回调中我操纵ObjectResponse来提取我的List然后传递给我的适配器.

现在,我有这样的事情

Call<ObjectResponse> call = apiInterface.getMyWholeObject();

call.enqueue(new Callback<ObjectResponse>() {
            @Override
            public void onResponse(Call<ObjectResponse> call, Response<ObjectResponse> response) {

                //various manipulation based on response.body() that in the ends 
                // lead to a List<SingleObject>

               mView.sendToAdapter(listSingleObject)
              }

            @Override
            public void onFailure(Call<ObjectResponse> call, 
                  Throwable t) {
                t.printStackTrace();
            }
         });
Run Code Online (Sandbox Code Playgroud)

我的问题是:

有没有办法从改造中获得一个可以最终引导我发出SingleObject列表(并操纵它)的Observable,而不必像改装回调中那样操纵ObjectResponse?或者我是否应该坚持使用改装回调,并且只有在obatin List之后我才可以在将此列表提供给我的适配器之前使用RxJava进行操作?

我想得到这样的东西

        apiInterface
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<List<SingleObject>>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(List<Post> posts) {

                  mView.sendToAdapter(listSingleObject)
                }
            });
Run Code Online (Sandbox Code Playgroud)

azi*_*ian 6

改造转换器工厂非常好地解决了这个问题.

杰克沃顿在他的"让改造为你工作"谈话中谈到"信封"对象,并指出如何解决这个问题.

定义了一个信封类 - 一个带有一些您不关心的额外字段的类:

public class Envelope<T> {
    Meta meta;
    List<Notification> notifications;
    T response;
}
Run Code Online (Sandbox Code Playgroud)

在这个POJO字段中meta并且List<Notification>从后端返回,但在android app的上下文中,它们对我们来说并不感兴趣.假设您需要从响应中获得的实际值是字段命名response,可能是任何对象(因为它是通用的).

特别是在您的示例中,POJO结构将如下所示:

public class OriginalResponse {
    HigherLevel higher_level;
}

public class HigherLevel {
    Data data;
}

public class Data {
    List<ActualData> list;
}
Run Code Online (Sandbox Code Playgroud)

您必须实现自定义Converter.Factory:

public class EnvelopingConverter extends Converter.Factory {
    @Nullable
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        Type envelopedType = TypeToken.getParameterized(Envelope.class, type).getType();

        Converter<ResponseBody, Envelope<?>> delegate = retrofit.nextResponseBodyConverter(this, envelopedType, annotations);
        return body -> {
            Envelope<?> envelope = delegate.convert(body);
            // Here return the object that you actually are interested
            // in your example it would be:
            // originalResponse = delegate.convert(body);
            // return originalResponse.higher_level.data.list;
            return envelope.response;
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

将此转换器添加到您的改造构建器:


    new Retrofit.Builder()
            ...
            .addConverterFactory(new EnvelopingConverter())
            ...

然后在你的改装api界面而不是直接Single<OriginalResponse>返回Single<List<ActualData>>:

interface Service {
    @GET(...)
    Single<List<ActualData>> getFoo();
}
Run Code Online (Sandbox Code Playgroud)