2017-12-20 4 views
1

Asynchrone Nachrüstanforderung ist ein Rückruf mit 2 Methoden onResponse() und onFailure().Generische Art der Nachrüstung für den benutzerdefinierten Anrufadapter

Ich möchte nicht immer diese 2 Methoden überschreiben und für den Fehlerfall behandeln.

Also, wenn ich die Google GithubBrowserSample von ApiResponse durch wollen, die die Nachrüstung Antwort Body-Wrapping und wandeln den Fehler wie folgt:

public class ApiResponse<T> { 

    public final int code; 
    @Nullable 
    public final T body; 
    @Nullable 
    public final String errorMessage; 

    public ApiResponse(Throwable error) { 
     code = -1; 
     body = null; 
     if (error instanceof IOException) { 
      errorMessage = "No network error"; 
     } 
     else { 
      errorMessage = error.getMessage(); 
     } 
    } 

    public ApiResponse(Response<T> response) { 
     code = response.code(); 
     if (response.isSuccessful()) { 
      body = response.body(); 
      errorMessage = null; 
     } 
     else { 
      String message = null; 
      if (response.errorBody() != null) { 
       try { 
        message = response.errorBody().string(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
      if (message == null || message.trim().length() == 0) { 
       message = response.message(); 
      } 
      errorMessage = message; 
      body = null; 
     } 
    } 

    public boolean isSuccessful() { 
     return code >= 200 && code < 300; 
    } 
} 

Ialso wollen die Gson Wandler verwenden, um die Nachrüstung Antwort zu konvertieren und dann wickeln es mit ApiResponse.

Wenn ich wie verwenden

Call<ApiResponse<Result>> requestCall = webClient.request1(xxx,xxx); 
requestCall.enqueue(new Callback<ApiResponse<Result>> {}); 

Es Arbeit scheint nicht. Die JSON-Antwortdaten können nicht in das Result-Objekt geparst werden.

So denke ich über das Schreiben meiner eigenen benutzerdefinierten Call Adapter Referenz retrofit sample, um durch Retrofit Call zu ersetzen. Aber ich habe immer noch das Problem, generischen Typ zu konvertieren.

public class MyCallAdapterFactory extends CallAdapter.Factory { 
    @Nullable 
    @Override 
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { 

     if (getRawType(returnType) != MyCall.class) { 
      return null; 
     } 

     Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType); 
     Class<?> rawObservableType = getRawType(observableType); 
     if (rawObservableType != ApiResponse.class) { 
      throw new IllegalArgumentException("type must be a resource"); 
     } 
     if (! (observableType instanceof ParameterizedType)) { 
      throw new IllegalArgumentException("resource must be parameterized"); 
     } 
     Type bodyType = getParameterUpperBound(0, (ParameterizedType) observableType); 
     Executor executor = retrofit.callbackExecutor(); 
     return new MyCallAdapter<>(bodyType, executor); 
    } 
} 

public class MyCallAdapter<T> implements CallAdapter<T, MyCall<T>> { 

    private final Type responseType; 
    private final Executor callbackExecutor; 

    public MyCallAdapter(Type responseType, Executor callbackExecutor) { 
     this.responseType = responseType; 
     this.callbackExecutor = callbackExecutor; 
    } 

    @Override 
    public Type responseType() { 
     return null; 
    } 

    @Override 
    public MyCall<T> adapt(Call<T> call) { 
     return new MyCallImpl<>(call, callbackExecutor); 
    } 
} 

public class MyCallImpl<T> implements MyCall<T> { 
    private final Call<T> call; 

    private final Executor callbackExecutor; 

    MyCallImpl(Call<T> call, Executor callbackExecutor) { 
     this.call = call; 
     this.callbackExecutor = callbackExecutor; 
    } 

    @Override 
    public void enqueue(MyCallback<T> callback) { 
     call.enqueue(new Callback<T>() { 
      @Override 
      public void onResponse(Call<T> call, Response<T> response) { 
       /* This is the problem. it will seems wrap to ApiResponse<ApiResponse<Result>>> because T is <ApiResponse<Result>>. 
       */ 
       callback.onResult(new ApiResponse<>(response)); 
      } 

      @Override 
      public void onFailure(Call<T> call, Throwable t) { 
       /** This one is also the issue. */ 
       callback.onResult(new ApiResponse<>(t)); 
      } 
     }); 
    } 

    @Override 
    public void cancel() { 
     call.cancel(); 
    } 

    @Override 
    public MyCall<T> clone() { 
     return new MyCallImpl<>(call.clone(), callbackExecutor); 
    } 
} 


public interface MyCallback<T> { 

    void onResult(ApiResponse<T> response); 

} 

Der obige Code hat das Problem bei der Verarbeitung von doppelt parametrisierten generischen Typen. Ich weiß nicht, wie ich damit umgehen soll.

Auch diesen Code auch hier wird abstürzen

Caused by: java.lang.NullPointerException: type == null 
     at retrofit2.Utils.checkNotNull(Utils.java:286) 
     at retrofit2.Retrofit.nextResponseBodyConverter(Retrofit.java:324) 
     at retrofit2.Retrofit.responseBodyConverter(Retrofit.java:313) 
     at retrofit2.ServiceMethod$Builder.createResponseConverter(ServiceMethod.java:736) 
     at retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:169)  

Könnte jemand helfen, wie MyCall<ApiResponse<Result>> zu lassen MyCallback<ApiResponse<Result>> nennen enqueue mit? Ergebnis ist das Parsen des JSON-Dateninhalts mit dem Gson-Konverter.

public class MyCallAdapter<T> implements CallAdapter<T, MyCall<ApiResponse<T>>> { 

    public MyCall<ApiResponse<T>> adapt(Call<T> call) { 
     /* This one will have the problem after changing MyCall<T> to MyCall<ApiResponse<T>>, Parameterized type mismatch.*/ 
     return new MyCallImpl<>(call, callbackExecutor); 
    } 
} 

Kann mir jemand helfen, auf das Problem hinzuweisen?

+0

'@Override public Typ responseType() { Rückgabewert null; } 'Antwort AntwortType in dieser Methode – Rahul

+0

@Rahul, Vielen Dank für das Aufzeigen. Ich repariere es jetzt. –

+0

Sie sind willkommen – Rahul

Antwort

0

Ändern Sie MyCallAdapter, MyCallback und MyCallImpl. @Rahul weist auf den Antworttyp hin und jetzt funktioniert alles gut.

public class MyCallAdapter<T> implements CallAdapter<T, MyCall<ApiResponse<T>>> { 

    private final Type responseType; 
    private final Executor callbackExecutor; 

    public MyCallAdapter(Type responseType, Executor callbackExecutor) { 
     this.responseType = responseType; 
     this.callbackExecutor = callbackExecutor; 
    } 

    @Override 
    public Type responseType() { 
     return responseType; 
    } 

    @Override 
    public MyCall<ApiResponse<T>> adapt(Call<T> call) { 
     return new MyCallImpl<>(call, callbackExecutor); 
    } 
} 


    public interface MyCallback<T> { 

     void onResult(T response); 

    } 


public class MyCallImpl<T> implements MyCall<ApiResponse<T>> { 
    private final Call<T> call; 

    private final Executor callbackExecutor; 

    MyCallImpl(Call<T> call, Executor callbackExecutor) { 
     this.call = call; 
     this.callbackExecutor = callbackExecutor; 
    } 

    @Override 
    public void enqueue(MyCallback<ApiResponse<T>> callback) { 
     call.enqueue(new Callback<T>() { 
      @Override 
      public void onResponse(Call<T> call, Response<T> response) { 
       callback.onResult(new ApiResponse<>(response)); 
      } 

      @Override 
      public void onFailure(Call<T> call, Throwable t) { 
       callback.onResult(new ApiResponse<>(t)); 
      } 
     }); 
    } 

    @Override 
    public void cancel() { 
     call.cancel(); 
    } 

    @Override 
    public MyCall<ApiResponse<T>> clone() { 
     return new MyCallImpl<>(call.clone(), callbackExecutor); 
    } 
} 

Dies ist die korrekte Implementierung. Ja.

Verwandte Themen