简体   繁体   English

使用 Retrofit 2 获取和获取未知数据集

[英]Using Retrofit 2 For getting and fetching Unknown set of data

Retrofit is a wonderful library, it is simple to use and maintain, but My case is different, as we know, we should apply the stages of creating a retrofit api and response accordingly, Retrofit 是一个很棒的库,它易于使用和维护,但我的情况不同,正如我们所知,我们应该应用创建 Retrofit api 和相应响应的阶段,

retrofit instance:改造实例:

retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(new ErrorCallAdapter.MyCallAdapterFactory())
                .client(httpClient)
                .build();
        return retrofit;

API Interface: API接口:

 @GET("api/getTheResults")
 ErrorCallAdapter.MyCall<GeneralResponse<SomeEntity> getGenericMethod();

part of the ErrorCallAdapter: ErrorCallAdapter 的一部分:

@Override
        public void enqueue(final MyCallback<Object> callback) {
            call.enqueue(new Callback<GeneralResponse<T>>() {
                @Override
                public void onResponse(final Call<GeneralResponse<T>> call, final Response<GeneralResponse<T>> response) {
                    final int code = response.code();
                    mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (response.isSuccessful()) {
                                if (response.body().getStatus() == 1) {
                                    callback.onResult(response.body().getResponse());
                                } else
                                    callback.onError(response.body().getMError());
                            } else
                                callback.onError(new MError(code,
                                        response.message() != null ? response.message() : "onResponse error"));
                        }
                    });
                }

                @Override
                public void onFailure(Call<GeneralResponse<T>> call, Throwable t) {
                    if (t != null)
                        callback.onError(new MError(501,
                                t.getMessage() != null ? t.getMessage() : "unexpected error"));
                    else
                        callback.onError(new MError(501,
                                "unexpected error"));
                }
            });

        }

part of fetching Data:获取数据的一部分:

public void loadUserSetupData() {
        ErrorCallAdapter.MyCall<GeneralResponse<Data>, Data> DataCall = apiManager.getData();
        setupDataMyCall.enqueue(new ErrorHandlingCallAdapter.MyCallback<Data>() {
            @Override
            public void onResult(Data data) {
                endProgressDialog();

                apiResult.onSuccess(data);
            }

            @Override
            public void onError(MError mError) {
                endProgressDialog();
                apiResult.onError(mError.getErrorMessage(mContext));
            }
        });
    }

The data I am Trying to fetch is in JSON Format as:我试图获取的数据采用 JSON 格式:

{
    "Status": 1,
    "Error": null,
    "ResponseList": [
        {
            "ErCode": 0,
            "Masseg": null,
            "DType": "OnceData",
            "Contents": {
                "VList": [{
                    "name":"name"
                    "name":"name"
                    "name":"name"
                  }],
                "WList": [{
                    "name":"name"
                    "name":"name"
                    "name":"name"
                  }, {
                    "name":"name"
                    "name":"name"
                    "name":"name"
                  }],
                "UList": [{
                    "name":"name"
                    "dd":"ddd" "DobledataType"
                    "object":"name"  "object data type"
                  }, {
                    "name":"name"
                    "int":"1"
                    "code":"15.00" "float data type
                  }],

            }
        }
    ]
}

"Above I refer to "name" as an entity object ( each of UList, VList, WList are objects for illustration only). “上面我将“名称”称为实体对象(每个 UList、VList、WList 都是仅用于说明的对象)。

My Question is : how can I make the retrofit works for any type of data where it will fetch the object whatever type it is, means I don't know if the "Contents" list will have specific type of object, I want to make it work where I can receive any type whatever it types is without knowing the object, we can specify the msg, the DType ( know in previous that DType = data for example will do some action) but we don't know what is the type of the response object (arraylist of strings, objects, integers , or just one string) How are we do that in retrofit Android?我的问题是:如何使改造适用于任何类型的数据,它可以获取任何类型的对象,这意味着我不知道“内容”列表是否具有特定类型的对象,我想制作它适用于我可以在不知道对象的情况下接收任何类型的任何类型,我们可以指定 msg、DType(例如之前知道 DType = data 将执行某些操作)但我们不知道类型是什么响应对象(字符串、对象、整数或仅一个字符串的数组列表)我们如何在改造 Android 中做到这一点?

If you can never know at all what is the content of the "Contents" field is, you can maybe set it directly as a JSONObject in your model, but then you will have to do some work everytime you want to retrieve something from the contents field.如果您永远无法知道“Contents”字段的内容是什么,您可以将其直接设置为模型中的 JSONObject,但是每次您想从内容中检索某些内容时,您都必须做一些工作场地。

However, if you know what type it can have, for example you know for sure it will be either an array of String, a String or an int, then you have the solution of using a custom GSON deserializer .但是,如果您知道它可以具有什么类型,例如您确定它是 String、String 或 int 数组,那么您就有了使用自定义GSON deserializer的解决方案。

First you would have to change your Model/Pojo to handle every types, for instance:首先,您必须更改 Model/Pojo 以处理每种类型,例如:

abstract class Model {
    // put here all the fields you know the type is stable
}

// for when content is a list
public class ListModel extends Model {
    @SerializedName("Contents")
    List<String> content;
}

// for when content is a String
public class StringModel extends Model {
    @SerializedName("Contents")
    String content;
}

// add every other derived class you need for the other types that the content field can have

Now you can create a deserializer that will return the correct Model object:现在您可以创建一个反序列化器来返回正确的模型对象:

public class ModelDeserializer implements JsonDeserializer<Model> {
    @Override
    public Model deserialize(JsonElement json, Type typeOfT, 
                             JsonDeserializationContext context) 
                             throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();

        // get the "contents" field
        JsonElement contents = jsonObject.get("Contents");
        if (contents != null) {
            if (contents.isJsonArray()) { // if this is a list, parse as ListModel
                return context.deserialize(jsonObject, 
                    ListModel.class);
            }
            if (contents.isJsonPrimitive()) { // json primitives are number, string, bool, character
                if (contents.getAsJsonPrimitive().isString() {
                    return context.deserialize(jsonObject, StringModel.class);
                }
            }
            // do the same for every other type you might have
        }
        return null;
    }
}

and finally, you will have to tell Retrofit and Gson to use that deserializer:最后,您必须告诉 Retrofit 和 Gson 使用该解串器:

Gson gson = new GsonBuilder()
         .registerTypeAdapter(Model.class, new ModelDeserializer())
         .create();

// just add the new gson object to your converterfactory
retrofit = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(new ErrorCallAdapter.MyCallAdapterFactory())
            .client(httpClient)
            .build();
    return retrofit;

and it should work.它应该工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM