Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


¿Cómo puedo devolver String o JSONObject de devolución de llamada asíncrona usando Retrofit?

Por ejemplo, llamar al

api.getUserName(userId, new Callback<String>() {...}); 

porque:

 retrofit.RetrofitError: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2 

Creo que debo deshabilitar el análisis de Gson en POJOs pero no puedo averiguar cómo hacerlo.

7 Solutions collect form web for “¿Cómo puedo devolver String o JSONObject de devolución de llamada asíncrona usando Retrofit?”

Me lo imaginé. Es embarazoso pero fue muy simple … La solución temporal puede ser así:

  public void success(Response response, Response ignored) { TypedInput body = response.getBody(); try { BufferedReader reader = new BufferedReader(new InputStreamReader(body.in())); StringBuilder out = new StringBuilder(); String newLine = System.getProperty("line.separator"); String line; while ((line = reader.readLine()) != null) { out.append(line); out.append(newLine); } // Prints the correct String representation of body. System.out.println(out); } catch (IOException e) { e.printStackTrace(); } } 

Pero si desea obtener directamente Callback la mejor manera es utilizar el convertidor .

 public class Main { public interface ApiService { @GET("/api/") public void getJson(Callback<String> callback); } public static void main(String[] args) { RestAdapter restAdapter = new RestAdapter.Builder() .setClient(new MockClient()) .setConverter(new StringConverter()) .setEndpoint("http://www.example.com").build(); ApiService service = restAdapter.create(ApiService.class); service.getJson(new Callback<String>() { @Override public void success(String str, Response ignored) { // Prints the correct String representation of body. System.out.println(str); } @Override public void failure(RetrofitError retrofitError) { System.out.println("Failure, retrofitError" + retrofitError); } }); } static class StringConverter implements Converter { @Override public Object fromBody(TypedInput typedInput, Type type) throws ConversionException { String text = null; try { text = fromStream(typedInput.in()); } catch (IOException ignored) {/*NOP*/ } return text; } @Override public TypedOutput toBody(Object o) { return null; } public static String fromStream(InputStream in) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder out = new StringBuilder(); String newLine = System.getProperty("line.separator"); String line; while ((line = reader.readLine()) != null) { out.append(line); out.append(newLine); } return out.toString(); } } public static class MockClient implements Client { @Override public Response execute(Request request) throws IOException { URI uri = URI.create(request.getUrl()); String responseString = ""; if (uri.getPath().equals("/api/")) { responseString = "{result:\"ok\"}"; } else { responseString = "{result:\"error\"}"; } return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes())); } } } 

Si sabe cómo mejorar este código, no dude en escribir sobre él.

Una posible solución sería utilizar JsonElement como el tipo de Callback<JsonElement> ( Callback<JsonElement> ). En su ejemplo original:

 api.getUserName(userId, new Callback<JsonElement>() {...}); 

En el método de éxito, puede convertir el JsonElement en String o JsonObject .

 JsonObject jsonObj = element.getAsJsonObject(); String strObj = element.toString(); 

Retrofit 2.0.0-beta3 agrega un módulo converter-scalars proporciona un Converter.Factory para convertir String , los 8 tipos primitivos y los 8 tipos primitivos en caja como cuerpos text/plain . Instale esto antes de su conversor normal para evitar pasar estos simples escalares a través, por ejemplo, de un convertidor JSON.

Por lo tanto, primero agregue el módulo de converter-scalars al archivo build.gradle para su aplicación.

 dependencies { ... // use your Retrofit version (requires at minimum 2.0.0-beta3) instead of 2.0.0 // also do not forget to add other Retrofit module you needed compile 'com.squareup.retrofit2:converter-scalars:2.0.0' } 

A continuación, cree su instancia de Retrofit esta manera:

 new Retrofit.Builder() .baseUrl(BASE_URL) // add the converter-scalars for coverting String .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(Service.class); 

Ahora puede utilizar la declaración de la API de la siguiente manera:

 interface Service { @GET("/users/{id}/name") Call<String> userName(@Path("userId") String userId); // RxJava version @GET("/users/{id}/name") Observable<String> userName(@Path("userId") String userId); } 

La respuesta puede ser mucho más corta de lo que ya se ha mencionado y no requiere bibliotecas adicionales:

En la declaración, use la Response como sigue:

 ... Callback<Response> callback); 

Y mientras se maneja la respuesta:

 @Override public void success(Response s, Response response) { new JSONObject(new String(((TypedByteArray) response.getBody()).getBytes())) } 

Cuando @lordmegamax respuesta completamente trabajo hay mucho mejor solución que viene de

Okio es una nueva biblioteca que complementa java.io y java.nio

Otros proyectos de cuadrados que ya apretado con retrofit y por lo tanto no es necesario agregar ninguna nueva dependencia y tiene que ser confiable:

 ByteString.read(body.in(), (int) body.length()).utf8(); 

ByteString es una secuencia inmutable de bytes. Para los datos de caracteres, String es fundamental. ByteString es el hermano perdido de String, lo que facilita tratar los datos binarios como un valor. Esta clase es ergonómica: sabe codificar y descodificarse como hex, base64 y UTF-8.

Ejemplo completo:

 public class StringConverter implements Converter { @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { try { return ByteString.read(body.in(), (int) body.length()).utf8(); } catch (IOException e) { throw new ConversionException("Problem when convert string", e); } } @Override public TypedOutput toBody(Object object) { return new TypedString((String) object); } } 

Esto es lo que hice, después de meter en el depurador. Nota: esto es para conseguirlo dentro de un error de devolución de llamada, no el éxito de devolución de llamada.

Verá que el tipo de éxito se encuentra llamando retrofitError.getSuccessType() y devuelve y objeto del tipo Type

A continuación, puede llamar retrofitError.getBodyAs(YourType.class) que es todo lo que necesitaba hacer porque para mí su siempre la clase que espero que sea.

Aquí está la respuesta de una línea:

 retrofitError.getBodyAs(retrofitError.getSuccessType()) 

Ahora, voy a notar que no tengo que hacer algo como esto con respecto a la devolución de llamada de éxito porque ya está funcionando mágicamente.

Para obtener llamada JSONObject o JSONArray

Puede crear una fábrica personalizada o copiarla desde aquí: https://github.com/marcinOz/Retrofit2JSONConverterFactory

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.