usar usando studio implementar desde consumir como android retrofit retrofit2

android - usando - ¿Cómo puedo devolver String o JSONObject desde la devolución de llamada asíncrona utilizando Retrofit?



retrofit rest android (7)

Por ejemplo, llamando

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 encontrar la manera de hacerlo.


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

Por lo tanto, primero agregue el módulo converter-scalars build.gradle 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'' }

Luego, crea tu 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 puedes usar la declaración API como esta:

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); }


Cuando la respuesta de @lordmegamax funciona completamente, hay una solución mucho mejor que proviene de

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

proyecto de otros cuadrados que ya está ajustado con la 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 datos de personajes, String es fundamental. ByteString es el hermano perdido de String, lo que facilita el tratamiento de los datos binarios como un valor. Esta clase es ergonómica: sabe cómo codificarse y decodificarse como hexadecimal, 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 hurgar en el depurador. Nota: esto es para realmente obtenerlo dentro de una devolución de llamada de error, no la devolución de llamada correcta.

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

Luego puedes llamar a retrofitError.getBodyAs(YourType.class) que es todo lo que necesitaba hacer porque para mí es siempre la clase que espero que sea.

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

retrofitError.getBodyAs(retrofitError.getSuccessType())

Ahora, me doy cuenta de que no tengo que hacer nada como esto con respecto a la devolución de llamada exitosa porque ya está funcionando mágicamente.


La respuesta puede ser mucho más corta de lo que ya se mencionó y no requiere ninguna biblioteca adicional:

En la declaración, use la Response siguiente manera:

... 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())) }


Me lo imaginé. Es vergonzoso, 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 Converter .

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 JsonElement en una String o un JsonObject .

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