Android:dynamically pass model class to retrofit callback

后端 未结 10 1787
伪装坚强ぢ
伪装坚强ぢ 2020-12-05 04:34

In retrofit to map json response to pojo usually we do this

@POST
Call getDataFromServer(@Url String url, @Body HashMap ha         


        
10条回答
  •  无人及你
    2020-12-05 05:07

    I use following approach: First I have implemented custom Call

    public class ProxyConvertCall implements Call {
        Converter converter;
        Call innerCall;
    
        public ProxyConvertCall2(Call jcall, Converter converter){
            this.innerCall = jcall;
            this.converter = converter;
            }
    
        @Override
        public Response execute() throws IOException {
            Response response = innerCall.execute();
            if (response.isSuccessful()){
                return Response.success(converter.Convert(response.body()),response.raw());
            }
            else return Response.error(response.code(), response.errorBody());
        }
    
        @Override
        public void enqueue(final Callback callback) {
            final Call self = this;
            this.innerCall.enqueue(new Callback() {  
                @Override
                public void onResponse(Call call, Response response) {
                    if (response.isSuccessful()){
                        callback.onResponse(self, Response.success(converter.Convert(response.body()), response.raw()));
                    }
                    else callback.onResponse(self, Response.error(response.code(), response.errorBody()));
                }
                @Override
                public void onFailure(Call call, Throwable t) {
                    callback.onFailure(self,t);
                }
            });
    
        }
    
        @Override
        public boolean isExecuted() {
            return innerCall.isExecuted();
        }
    
        @Override
        public void cancel() {
            innerCall.cancel();
    
        }
    
        @Override
        public boolean isCanceled() {
            return innerCall.isCanceled();
        }
    
        @Override
        public Call clone() {
            return new ProxyConvertCall2<>(innerCall,converter);
        }
    
        @Override
        public Request request() {
            return innerCall.request();
        }
    }
    

    It wrappes Call and converts it's result to by converter.

    @FunctionalInterface 
    public interface Converter {
        public Tout Convert(Tin in);
    }
    

    For your service you must create service interface, that return JsonObject for single object and JsonArray for arrays

    public interface ApiCalls {
        @POST
        Call getDataFromServer(@Url String url, @Body HashMap hashMap);
    
        @POST
        Call getArrayFromServer(@Url String url, @Body HashMap hashMap);
    }
    

    Then wrap it with generic class, with converters from JsonElement to any Type :

    public class ApiCallsGeneric {
        Converter fromJsonObject;
        Converter> fromJsonArray;
        ApiCalls service;
    
        public ApiCallsGeneric(Class classOfT, ApiCalls service){    
            this.service = service;
            Gson gson  = new GsonBuilder().create();
            GenericListType genericListTypeOfT = new GenericListType(classOfT);
            fromJsonObject = (t)->gson.fromJson(t,classOfT);
            fromJsonArray =(t)->gson.fromJson(t,genericListTypeOfT);
        }
    
        public Call getDataFromServer(String url, HashMap hashMap){
            return new ProxyConvertCall<>(service.getDataFromServer(url, hashMap), fromJsonObject);
         }
    
        public Call> getArrayFromServer(String url, HashMap hashMap){ 
            return new ProxyConvertCall<>(service.getArrayFromServer(url, hashMap), fromJsonArray);
         }
    }
    

    GenericListType is ParaterizedType. It is used for passing type parameter to gson for List

    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;
    
    public class GenericListType implements ParameterizedType {
    
        private Type wrapped;
    
        public GenericListType(Type wrapped) {
            this.wrapped = wrapped;
        }
    
        public Type[] getActualTypeArguments() {
            return new Type[] {wrapped};
        }
    
        public Type getRawType() {
            return  List.class;
        }
    
        public Type getOwnerType() {
            return null;
        }
    
    }
    

    Then you can instantiate ApiCallsGeneric with type you want.

    ApiCallsGeneric userService= new ApiCallsGeneric(User.class, retrofit.create(ApiCalls.class));
    Call call = userService.getDataFromServer(StringConstants.URL,hashMap);
    call.enqueue(new Callback() {
             //Response and failure callbacks
        }
    

提交回复
热议问题