Android:动态传递模型类以改进回调

时间:2016-12-01 05:53:02

标签: android retrofit retrofit2 pojo

在改造中将json响应映射到pojo通常我们这样做

@POST
Call<User> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

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

用户是我的Pojo课程。 但是对于每个其他请求,我需要制作不同的pojo并为改进调用编写相同的代码。我想制作一个单独的方法来调用api并传递相应的pojo类来改进调用。像这样

ApiCalls api = retrofit.create(ApiCalls.class);
Call<*ClassPassed*> call = api.getDataFromServer(StringConstants.URL,hashMap);
call.enqueue(new Callback<*ClassPassed*>() {
     //Response and failure callbacks
}

所以现在我可以将任何pojo类转换为单个方法并获得响应。这只是为了避免一次又一次地重写相同的代码。这可能是

更新 详细说明:

假设我需要提出两个请求。第一个是获取userDetails,另一个是patientDetails。所以我必须创建两个模型类User和Patient。 因此,在改造中,我会有类似的东西

@POST
Call<User> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

@POST
Call<Patient> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

在我的FragmentUser和FragmentPatient类中,我将会这样做

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

ApiCalls api = retrofit.create(ApiCalls.class);
Call<Patient> call = api.getDataFromServer(StringConstants.URL,hashMap);
call.enqueue(new Callback<Patient>() {
     //Response and failure callbacks
}

但是这里的代码只是因为不同的pojo类而被修复。我需要在每个其他片段中为不同的请求重复相同的代码。 所以我需要制作一个通用的方法,它可以接受任何pojo类,然后从片段我只是传递pojo进行映射。

10 个答案:

答案 0 :(得分:13)

  

Android:动态传递模型类以改进回调

有两种方法可以做到这一点.........

<强> 1。泛型

<强> 2。将所有POJO合并为一个......

  

<强>泛型

在泛型中,你必须通过类传递方法。请看示例.....

ApiCalls api = retrofit.create(ApiCalls.class);

Call<User> call = api.getDataFromServer(StringConstants.URL,hashMap);

callRetrofit(call,1);

 public static <T> void callRetrofit(Call<T> call,final int i) {

        call.enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
            if(i==1){
                  User user = (User) response.body(); // use the user object for the other fields
             }else if (i==2){
                 Patient user = (Patient) response.body(); 
              }


            }

            @Override
            public void onFailure(Call<T> call, Throwable t) {

            }
        });

    }

注意: - 上述改造调用TypeCast您的回复YOUR OBJECT,以便您可以访问其字段和方法

  

将所有POJO合并为一个

它非常易于使用。您必须将所有POJO类合并为一个并在Retrofit中使用它们。请看下面的例子......

  

我有两个API登录和用户......

在Login API中,我得到了像这样的JSON响应......

  

{“成功”:是的,“消息”:“身份验证成功”}

高于JSON,POJO看起来像这样

public class LoginResult{

    private String message;
    private boolean success;

    //constructor , getter and setter 
}

和Retrofit调用看起来像这样......

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


                }

                @Override
                public void onFailure(Call<LoginResult> call, Throwable t) {

                }
            });

在User API中,我得到了像这样的JSON响应..

  

{“name”:“sushildlh”,“place”:“hyderabad”}

高于JSON,POJO看起来像这样

 public class UserResult{

        private String name;
        private String place;

        //constructor , getter and setter 
    }

和Retrofit调用看起来像这样......

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


                }

                @Override
                public void onFailure(Call<UserResult> call, Throwable t) {

                }
            }); 

只需将上述两种JSON响应合并为一个......

public class Result{

            private String name;
            private String place;
            private String message;
            private boolean success;

            //constructor , getter and setter 
        }

并在您的API调用中使用结果......

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


            }

            @Override
            public void onFailure(Call<Result> call, Throwable t) {

            }
        }); 

注意: - 您直接组合您的2 POJO类并访问它。 (如果您的响应非常大,并且如果某些KEY与不同的变量类型相同则提供重复,这非常复杂)

答案 1 :(得分:10)

你可以像这样构建主要的pojo

public class BaseResponse<T>
{
    @SerializedName("Ack")
    @Expose
    private String ack;

    @SerializedName("Message")
    @Expose
    private String message;

    @SerializedName("Data")
    @Expose
    private T data;

    /**
     *
     * @return
     * The ack
     */
    public String getAck() {
        return ack;
    }

    /**
     *
     * @param ack
     * The Ack
     */
    public void setAck(String ack) {
        this.ack = ack;
    }

    /**
     *
     * @return
     * The message
     */
    public String getMessage() {
        return message;
    }

    /**
     *
     * @param message
     * The Message
     */
    public void setMessage(String message) {
        this.message = message;
    }


    /**
     *
     * @return
     * The data
     */
    public T getData() {
        return data;
    }

    /**
     *
     * @param data
     * The Data
     */
    public void setData(T data) {
        this.data = data;
    }
}

并像这样打电话

 Call<BaseResponse<SetupDetails>> getSetup(@Query("site_id") int id,@Query("ino") String ii);

答案 2 :(得分:1)

首先创建界面:

public interface
ItemAPI {

    @GET("setup.php")
    Call<SetupDetails> getSetup(@Query("site_id") int id,@Query("ino") String ii);

    @GET("setup.php")
    void setMy(@Query("site_id") int id, Callback<List<SetupDetails>> sd);
    }

现在创建类:

public class Apiclient {

    private static final String BASE_URL ="http://www.YOURURL.COM/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {

        OkHttpClient.Builder httpClient2 = new OkHttpClient.Builder();
        httpClient2.addNetworkInterceptor(new Interceptor() {

            @Override
            public Response intercept(Chain chain) throws IOException {
                Request.Builder builder = chain.request().newBuilder();
                builder.addHeader("site_id","1");
                return chain.proceed(builder.build());
            }
        });
        OkHttpClient client = httpClient2.build();

        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }

现在在任何活动中只需使用:

ItemAPI itemAPI = Apiclient.getClient().create(ItemAPI.class);
     Call<AllProducts> call=itemAPI.getSetup(1,count);
     call.enqueue(new Callback<AllProducts>() {
            @Override
            public void onResponse(Call<AllProducts> call, Response<AllProducts> response) {
                try {
                    if (response.body().getItem().size()>0){

                    }

                }catch (Exception e){
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailedAfterRetry(Throwable t) {

            }
        });

答案 3 :(得分:1)

我的方法是制作一个名为ResponseData的POJO,你将拥有一个属性Object,所以你有:

@POST
Call<ResponseData> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

当您收到回复时,您必须将您的response.body()解析为所需的类。专业人士:你只需要一个请求,而不必解析响应。

答案 4 :(得分:1)

这样做:

    @POST
    Call<Object> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

    ApiCalls api = retrofit.create(ApiCalls.class);
        Call<Object> call = api.getDataFromServer(StringConstants.URL,hashMap);
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<Object> call, Response<Object> response) {
            YourModel modelObject = (YourModel) response.body();
            }

            @Override
            public void onFailure(Call<Object> call, Throwable t) {

            }
        }

答案 5 :(得分:1)

为了概括您想要的内容,您只需序列化您的POJO,然后您就可以将POJO原样传递给方法。 当你使用Objects进行序列化时,它基本上将它转换为字符串,后来转换为一个大的Json字符串,更容易传输和操作。

一个简单的例子是:

示例POJO实现序列化,在这里你应该确保Map<String,Object>中的字符串对应于服务器期望获得的字符串,并且每个POJO中的方法应该不同:

public class YourPojo implements ObjectSerializer
{
  private static final long serialVersionUID = -1481977114734318563L;

  private String itemName;
  private int itemId;

  @Override
  public Map<String, Object> objectSerialize()
  {
   Map<String, Object> map = new HashMap<>();
   map.put("itemid", itemId); // server will be looking for "itemid"
   map.put("itemname", itemName); // server will be looking for "itemname"
   }

   //other stuff you need....
 }

序列化接口(因此您可以跨其他POJO实现它)

public interface ObjectSerializer extends Serializable
{
  public Map<String, Object> objectSerialize();
}

你可能有一个Json解析器:

public class JsonParser
{
  public static JSONObject serializeToJsonString(Map<String, Object> jsonParams)
  {
    Gson gson = new Gson();
    String json = gson.toJson(jsonParams);
    JSONObject object;
    try
    {
        object = new JSONObject(json);
    }
    catch (Exception e)
    {
        object = new JSONObject(jsonParams);
    }
    return (object);
 }
}

最后,你的API定义:

@POST("users/createitem")
Call<ResponseBody> someCall(@Body RequestBody params);

和方法,它应该位于管理您的请求的通用类中:

public void someMethodName(YourPojo item, final CustomEventListener<String> listener)
{
    JSONObject object = JsonParser.serializeToJsonString(item.objectSerialize());
    RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8";), object.toString());
    Call<ResponseBody> requestCall = serviceCaller.someCall(body);

    requestCall.enqueue(new Callback<ResponseBody>()
    {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
        {
            try
            {
                String response = rawResponse.body().string();
                //do what you want with this string
                listener.getResult(response);
            }
            catch (Exception e)
            {
             e.printStackTrace();                    
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable throwable)
        {

        }
    });
    }

我通过听众返回回复,这是你可以做的一个例子,取决于你的回应。

希望这有帮助!

答案 6 :(得分:1)

您需要使用泛型。这样,您就可以将所需的类型传递给调用。

@POST
Call<T> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap, Class<T> requestClass);

ApiCalls api = retrofit.create(ApiCalls.class);
    Call<T> call = api.getDataFromServer(StringConstants.URL,hashMap);
    call.enqueue(new Callback<T>() {
         //Response and failure callbacks
    }

顺便说一下,我没有改装专家(我主要使用自己的东西),但我认为你错了。

答案 7 :(得分:0)

使用标准泛型,有一点点黑客攻击

像这样定义你的界面

public interface ApiCalls<T> {
    @POST
    Call<T> getResult getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);
}

并要求创建api客户端使用辅助方法

class HelperMethods {
    @SuppressWarnings("unchecked")
    private static <T> ApiCalls<T> getClient() {
        return retrofit.create((Class<ApiCalls<T>>)(Class<?>)ApiCalls.class);
    }
}

ApiCalls<User> api = HelperMethods.getClient();

但是,尽管已经有多少次在这里说过,我会再说一遍......不要这样做......你放弃了Retrofit提供的整个类型安全和合同验证..这实际上是最激动人心的事情..

答案 8 :(得分:0)

我使用以下方法: 首先,我实现了自定义调用

public class ProxyConvertCall<Tin,Tout> implements Call<Tout> {
    Converter<Tin,Tout> converter;
    Call<Tin> innerCall;

    public ProxyConvertCall2(Call<Tin> jcall, Converter<Tin,Tout> converter){
        this.innerCall = jcall;
        this.converter = converter;
        }

    @Override
    public Response<Tout> execute() throws IOException {
        Response<Tin> 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<Tout> callback) {
        final Call<Tout> self = this;
        this.innerCall.enqueue(new Callback<Tin>() {  
            @Override
            public void onResponse(Call<Tin> call, Response<Tin> 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<Tin> 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<Tout> clone() {
        return new ProxyConvertCall2<>(innerCall,converter);
    }

    @Override
    public Request request() {
        return innerCall.request();
    }
}

它包裹Call<Tin>并通过转换器将其结果转换为<Tout>

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

对于您的服务,您必须创建服务接口,返回单个对象的JsonObject和数组的JsonArray

public interface ApiCalls {
    @POST
    Call<JsonObject> getDataFromServer(@Url String url, @Body HashMap<String,Object> hashMap);

    @POST
    Call<JsonArray> getArrayFromServer(@Url String url, @Body HashMap<String,Object> hashMap);
}

然后用泛型类包装它,将JsonElement中的转换器包装到任何类型<T>

public class ApiCallsGeneric<T> {
    Converter<JsonObject,T> fromJsonObject;
    Converter<JsonArray,List<T>> fromJsonArray;
    ApiCalls service;

    public ApiCallsGeneric(Class<T> classOfT, ApiCalls service){    
        this.service = service;
        Gson gson  = new GsonBuilder().create();
        GenericListType<T> genericListTypeOfT = new GenericListType<T>(classOfT);
        fromJsonObject = (t)->gson.fromJson(t,classOfT);
        fromJsonArray =(t)->gson.fromJson(t,genericListTypeOfT);
    }

    public Call<T> getDataFromServer(String url, HashMap<String,Object> hashMap){
        return new ProxyConvertCall<>(service.getDataFromServer(url, hashMap), fromJsonObject);
     }

    public Call<List<T>> getArrayFromServer(String url, HashMap<String,Object> hashMap){ 
        return new ProxyConvertCall<>(service.getArrayFromServer(url, hashMap), fromJsonArray);
     }
}

GenericListType是ParaterizedType。它用于将类型参数传递给List<T>

的gson
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class GenericListType<T> 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;
    }

}

然后,您可以使用所需的类型实例化ApiCallsGeneric

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

答案 9 :(得分:0)

在Response中使用JsonElement会有所帮助:

     public interface serviceApi {
     //  @GET("userinfo")
    //  Observable<userInfo> getUserIfo();
    @GET("gmail/v1/users/me/profile")
    Observable<Response<JsonElement>> getUserProfile(@HeaderMap 
    Map<String,String> Headers);
    }


private void executeAPICall(String token) {
    HashMap<String, String> headers = new HashMap<>();
    Observable<Response<JsonElement>> observable = RetroFitInstance.getInstance().getAPI(token)
            .getUserProfile(ImmutableMap.<String, String>of("Authorization", String.format("Bearer %s", token))).observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io());

    Observer<Response<JsonElement>> observer = new Observer<Response<JsonElement>>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {
            Log.d("error:", e.getMessage());
        }

        @Override
        public void onNext(Response<JsonElement> jsonElementResponse) {
            UserProfile userProfile = 
       getObject(jsonElementResponse,UserProfile.class);

            EmailTextView.setText("Email Address: " + 
            userProfile.getEmailAddress());
            EmailTextView.setText("Email Address: " + 
            userProfile.getEmailAddress());
            totalEmailsTextView.setText("Total Emails: " + userProfile.getMessagesTotal());
            totalThreadsTextView.setText("Total Threads: " + userProfil
    };
    subscription = observable.subscribe(observer);
}


private <T> T getObject(Response<JsonElement> jsonElementResponse, Class<T> 
                        t){
    return  new Gson().fromJson(jsonElementResponse.body().getAsJsonObject().toString(),t);
}