Cliente REST de Android, ¿Muestra?


115

Incluso si este hilo ha aceptado la respuesta, siéntase libre de proponer otras ideas, sí usa o le gusta


He conocido estos artículos:

Y eso me llevó a este video de Google I / O 2010 sobre aplicaciones cliente REST

Desde ahora, he estado creando un componente REST como componente estático en mi clase de controlador de aplicación.

A partir de ahora, creo, debería cambiar el patrón. Alguien señaló que la aplicación Google IOSched es una gran muestra de cómo escribir clientes REST en Android. Alguien más dijo que esta forma es demasiado complicada.

Entonces, ¿alguien puede mostrarnos cuál es la mejor práctica? De forma breve y sencilla.
La aplicación IOSched es demasiado compleja para un caso de uso de muestra.


Hola, Generalmente desarrollo un paquete separado para el servicio web llamado "ws", he generalizado la clase llamada "WebServicUtils.java". La clase WebServiceUtils.java tiene métodos para acceder al servicio web. No estoy seguro de si mi técnica es la mejor o no, pero es reutilizable cada vez que copio mi paquete ws en la aplicación de Android. Avísame si quieres saber más sobre mi técnica.
Ketan Parmar

No creo que el comentarista de YouTube tenga una mejor alternativa. Tenemos que trabajar dentro de las API de Android, incluso si a menudo son increíblemente complicadas y verbosas sin sentido.
Timmmm

Como nota al margen, Mechanoid, un complemento de eclipse de código abierto para Android puede generar clientes JSON-REST utilizando un DSL simple, puede encontrar una guía sobre cómo usarlo aquí robotoworks.com/mechanoid-plugin/service-client-dsl (Soy el autor de este complemento, ¡lo siento por el enchufe desvergonzado!)
Ian Warwick

Esto puede resultar muy útil para las personas que aprenden a implementar el cliente REST de Android. Transcripción de la presentación de Dobjanschi a PDF: drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…
Kay Zed

Respuestas:


99

EDICIÓN 2 (octubre de 2017):

Estamos en 2017. Solo use Retrofit. Casi no hay razón para usar otra cosa.

EDITAR:

La respuesta original tiene más de un año y medio en el momento de esta edición. Aunque los conceptos presentados en la respuesta original aún se mantienen, como señalan otras respuestas, ahora existen bibliotecas que facilitan esta tarea. Más importante aún, algunas de estas bibliotecas manejan los cambios de configuración del dispositivo por usted.

La respuesta original se conserva a continuación como referencia. Pero también tómese el tiempo para examinar algunas de las bibliotecas cliente de Rest para Android para ver si se ajustan a sus casos de uso. La siguiente es una lista de algunas de las bibliotecas que he evaluado. De ninguna manera pretende ser una lista exhaustiva.


Respuesta original:

Presentando mi enfoque para tener clientes REST en Android. Aunque no digo que sea el mejor :) Además, tenga en cuenta que esto es lo que se me ocurrió en respuesta a mi requisito. Es posible que deba tener más capas / agregar más complejidad si su caso de uso lo exige. Por ejemplo, no tengo ningún almacenamiento local; porque mi aplicación puede tolerar la pérdida de algunas respuestas REST.

Mi enfoque usa solo AsyncTasks bajo las sábanas. En mi caso, "llamo" a estas Tareas desde mi Activityinstancia; pero para tener en cuenta completamente casos como la rotación de pantalla, puede optar por llamarlos desde una Serviceo tal.

Elegí conscientemente mi propio cliente REST para que fuera una API. Esto significa que la aplicación que usa mi cliente REST ni siquiera necesita conocer las URL REST reales y el formato de datos utilizado.

El cliente tendría 2 capas:

  1. Capa superior: el propósito de esta capa es proporcionar métodos que reflejen la funcionalidad de la API REST. Por ejemplo, podría tener un método Java correspondiente a cada URL en su API REST (o incluso dos, uno para GET y otro para POST).
    Este es el punto de entrada a la API del cliente REST. Esta es la capa que la aplicación usaría normalmente. Podría ser un singleton, pero no necesariamente.
    Esta capa analiza la respuesta de la llamada REST en un POJO y la devuelve a la aplicación.

  2. Esta es la AsyncTaskcapa de nivel inferior , que utiliza métodos de cliente HTTP para salir y hacer esa llamada REST.

Además, elegí usar un mecanismo de devolución de llamada para comunicar el resultado de los mensajes de correo electrónico AsyncTaska la aplicación.

Basta de texto. Veamos algo de código ahora. Tomemos una URL de API REST hipotética: http://myhypotheticalapi.com/user/profile

La capa superior podría verse así:

   /**
 * Entry point into the API.
 */
public class HypotheticalApi{   
    public static HypotheticalApi getInstance(){
        //Choose an appropriate creation strategy.
    }
    
    /**
     * Request a User Profile from the REST server.
     * @param userName The user name for which the profile is to be requested.
     * @param callback Callback to execute when the profile is available.
     */
    public void getUserProfile(String userName, final GetResponseCallback callback){
        String restUrl = Utils.constructRestUrlForProfile(userName);
        new GetTask(restUrl, new RestTaskCallback (){
            @Override
            public void onTaskComplete(String response){
                Profile profile = Utils.parseResponseAsProfile(response);
                callback.onDataReceived(profile);
            }
        }).execute();
    }
    
    /**
     * Submit a user profile to the server.
     * @param profile The profile to submit
     * @param callback The callback to execute when submission status is available.
     */
    public void postUserProfile(Profile profile, final PostCallback callback){
        String restUrl = Utils.constructRestUrlForProfile(profile);
        String requestBody = Utils.serializeProfileAsString(profile);
        new PostTask(restUrl, requestBody, new RestTaskCallback(){
            public void onTaskComplete(String response){
                callback.onPostSuccess();
            }
        }).execute();
    }
}


/**
 * Class definition for a callback to be invoked when the response data for the
 * GET call is available.
 */
public abstract class GetResponseCallback{
    
    /**
     * Called when the response data for the REST call is ready. <br/>
     * This method is guaranteed to execute on the UI thread.
     * 
     * @param profile The {@code Profile} that was received from the server.
     */
    abstract void onDataReceived(Profile profile);
    
    /*
     * Additional methods like onPreGet() or onFailure() can be added with default implementations.
     * This is why this has been made and abstract class rather than Interface.
     */
}

/**
 * 
 * Class definition for a callback to be invoked when the response for the data 
 * submission is available.
 * 
 */
public abstract class PostCallback{
    /**
     * Called when a POST success response is received. <br/>
     * This method is guaranteed to execute on the UI thread.
     */
    public abstract void onPostSuccess();

}

Tenga en cuenta que la aplicación no usa JSON o XML (o cualquier otro formato) devuelto directamente por la API REST. En cambio, la aplicación solo ve el bean Profile.

Entonces, la capa inferior (capa AsyncTask) podría verse así:

/**
 * An AsyncTask implementation for performing GETs on the Hypothetical REST APIs.
 */
public class GetTask extends AsyncTask<String, String, String>{
    
    private String mRestUrl;
    private RestTaskCallback mCallback;
    
    /**
     * Creates a new instance of GetTask with the specified URL and callback.
     * 
     * @param restUrl The URL for the REST API.
     * @param callback The callback to be invoked when the HTTP request
     *            completes.
     * 
     */
    public GetTask(String restUrl, RestTaskCallback callback){
        this.mRestUrl = restUrl;
        this.mCallback = callback;
    }
    
    @Override
    protected String doInBackground(String... params) {
        String response = null;
        //Use HTTP Client APIs to make the call.
        //Return the HTTP Response body here.
        return response;
    }
    
    @Override
    protected void onPostExecute(String result) {
        mCallback.onTaskComplete(result);
        super.onPostExecute(result);
    }
}

    /**
     * An AsyncTask implementation for performing POSTs on the Hypothetical REST APIs.
     */
    public class PostTask extends AsyncTask<String, String, String>{
        private String mRestUrl;
        private RestTaskCallback mCallback;
        private String mRequestBody;
        
        /**
         * Creates a new instance of PostTask with the specified URL, callback, and
         * request body.
         * 
         * @param restUrl The URL for the REST API.
         * @param callback The callback to be invoked when the HTTP request
         *            completes.
         * @param requestBody The body of the POST request.
         * 
         */
        public PostTask(String restUrl, String requestBody, RestTaskCallback callback){
            this.mRestUrl = restUrl;
            this.mRequestBody = requestBody;
            this.mCallback = callback;
        }
        
        @Override
        protected String doInBackground(String... arg0) {
            //Use HTTP client API's to do the POST
            //Return response.
        }
        
        @Override
        protected void onPostExecute(String result) {
            mCallback.onTaskComplete(result);
            super.onPostExecute(result);
        }
    }
    
    /**
     * Class definition for a callback to be invoked when the HTTP request
     * representing the REST API Call completes.
     */
    public abstract class RestTaskCallback{
        /**
         * Called when the HTTP request completes.
         * 
         * @param result The result of the HTTP request.
         */
        public abstract void onTaskComplete(String result);
    }

Así es como una aplicación puede usar la API (en un Activityo Service):

HypotheticalApi myApi = HypotheticalApi.getInstance();
        myApi.getUserProfile("techie.curious", new GetResponseCallback() {

            @Override
            void onDataReceived(Profile profile) {
                //Use the profile to display it on screen, etc.
            }
            
        });
        
        Profile newProfile = new Profile();
        myApi.postUserProfile(newProfile, new PostCallback() {
            
            @Override
            public void onPostSuccess() {
                //Display Success
            }
        });

Espero que los comentarios sean suficientes para explicar el diseño; pero me complacerá brindar más información.


Me gusta más esta respuesta debido a ejemplos de código bastante agradable. Gracias
Marek Sebera

1
Probablemente no valga nada, esto realmente no sigue un patrón MVC RESTful adecuado, como lo describe Virgil Dobjanschi. Debería incorporar una capa ContentProvider completa, que usa una base de datos SQLite que la aplicación usa directamente. De lo contrario, este es un cliente REST bueno y ligero para Android.
Cooper

1
Una pequeña cosa, deberá llamar a ejecutar en esos Get / PostTask's
Mo Kargas

1
Esto es realmente grandioso. ¿Cómo haría que GetResponseCallback sea más genérico, para que no devuelva solo un perfil, o sugeriría hacer un GetResponseCallback separado para cada tipo de datos de la API?

1
@MichaelHerbig Sí, hay formas de hacer GetResponseCallbackmás genérico. La que prefiero es usar una interfaz de marcador : Me gusta interface IGetResopnse{} para denotar todas las clases que podrían ser respuestas. Entonces, tengo class Profile implements IGetResponseetc. Por último, hacen GetResponseCallbackgenérico con IGetResponseque el límite superior : public abstract class GetResponseCallback<? extends IGetResponse>.
curioso técnico

11

"El desarrollo de aplicaciones cliente REST para Android" de Virgil Dobjanschi generó mucha discusión, ya que no se presentó el código fuente durante la sesión ni se proporcionó posteriormente.

La única implementación de referencia que conozco (comente si sabe más) está disponible en Datadroid (la sesión de Google IO se menciona en / presentación). Es una biblioteca que puede usar en su propia aplicación.

El segundo enlace solicita el "mejor" marco REST, que se analiza en profundidad en stackoverflow. Para mí, el tamaño de la aplicación es importante, seguido del rendimiento de la implementación.

  • Normalmente uso la implementación simple org.json, que es parte de Android desde el nivel de API 1 y, por lo tanto, no aumenta el tamaño de la aplicación.
  • Para mí fue muy interesante la información que se encontró sobre el rendimiento de los analizadores JSON en los comentarios: a partir de Android 3.0 Honeycomb, el analizador de transmisión de GSON se incluye como android.util.JsonReader. Desafortunadamente, los comentarios ya no están disponibles.
  • Spring Android (que utilizo a veces) es compatible con Jackson y GSON. La documentación del módulo RestTemplate de Spring para Android apunta a una aplicación de muestra .

Por lo tanto, me quedo con org.json o GSON para escenarios más complejos. Para la arquitectura de una implementación org.json, estoy usando una clase estática que representa los casos de uso del servidor (por ejemplo, findPerson, getPerson). Llamo a esta funcionalidad desde un servicio y uso clases de utilidad que están haciendo el mapeo (específico del proyecto) y la IO de red (mi propia plantilla REST para GET o POST simple). Intento evitar el uso de la reflexión.


4
El libro de O'Reilly, Programming Android, presenta una implementación completa del patrón RESTful MVC de Dobjanschi (capítulos 12-13).
Cooper

Gracias por la pista: encontré esta declaración en Amazon: "Los capítulos 12 y 13 tratan con los proveedores de contenido. El tratamiento extenso de los proveedores de contenido con código de ejemplo y una aplicación de muestra me brindó varias ideas nuevas sobre cómo funciona esta tecnología y cómo puede utilizarse en situaciones de programación reales. El marco del proveedor de contenido para almacenar y hacer referencia a datos mediante URI es una de las características novedosas del sistema operativo Android. ¡Excelente trabajo explicando la tecnología paso a paso! "
ChrLipp

2
El código está en github.com/bmeike/ProgrammingAndroid2Examples (pero faltan capítulos, puede encontrarlos en el código de la primera edición github.com/bmeike/ProgrammingAndroidExamples )
ChrLipp

¿Alguien ha podido ejecutar este código en ICS +? El archivo de tareas pendientes del ejemplo de FinchVideo indica sucintamente "- Se bloquea en ICS". Me ha decepcionado un poco después de comprar el libro para descubrir el código ejemplos se rompen ...
eageranalyst

7

Nunca use AsynTask para realizar solicitudes de red o cualquier otra cosa que deba persistir. Async Task está fuertemente ligada a su actividad y si el usuario cambia la orientación de la pantalla desde que se vuelve a crear la aplicación, AsyncTask se detendrá.

Le sugiero que utilice el patrón de servicio con Intent Service y ResultReceiver. Eche un vistazo a RESTDroid . Es una biblioteca que le permite realizar cualquier tipo de solicitud REST de forma asincrónica y notificar a su interfaz de usuario con los oyentes de solicitudes que implementan el patrón de servicio de Virgil Dobjanschi.


3

Hay otra biblioteca con una API mucho más limpia y datos con seguridad de tipos. https://github.com/kodart/Httpzoid

Aquí hay un ejemplo de uso simple

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
    .data(new User("John"))
    .execute();

O más complejo con devoluciones de llamada

Http http = HttpFactory.create(context);
http.post("http://example.com/users")
    .data(new User("John"))
    .handler(new ResponseHandler<Void>() {
        @Override
        public void success(Void ignore, HttpResponse response) {
        }

        @Override
        public void error(String message, HttpResponse response) {
        }

        @Override
        public void failure(NetworkError error) {
        }

        @Override
        public void complete() {
        }
    }).execute();

Es nuevo y fresco, pero parece muy prometedor.


Parece que se está ejecutando en AsyncTask, lo que no es bueno para solicitudes de larga ejecución y cambios entre actividades, porque AsyncTask se eliminará cuando la actividad salga.
Malachiasz

1

Hay muchas bibliotecas y estoy usando esta: https://github.com/nerde/rest-resource . Esto fue creado por mí y, como puede ver en la documentación, es mucho más limpio y simple que los demás. No está enfocado en Android, pero lo estoy usando y está funcionando bastante bien.

Es compatible con la autenticación básica HTTP. Hace el trabajo sucio de serializar y deserializar objetos JSON. Te gustará, especialmente si tu API es similar a Rails.


1

Descargo de responsabilidad: estoy involucrado en el proyecto de código abierto rest2mobile

Otra alternativa como cliente REST es utilizar rest2mobile .

El enfoque es ligeramente diferente, ya que utiliza ejemplos de descanso concretos para generar el código de cliente para el servicio REST. El código reemplaza la URL REST y las cargas útiles JSON con métodos Java nativos y POJO. También maneja automáticamente las conexiones del servidor, las invocaciones asincrónicas y las conversiones de POJO a / desde JSON.

Tenga en cuenta que esta herramienta viene en diferentes sabores (cli, complementos, soporte para android / ios / js) y puede usar el complemento de estudio de Android para generar la API directamente en su aplicación.

Todo el código se puede encontrar en github aquí .


3
Reemplace el primer vínculo con el objetivo real en lugar de anunciar su sitio.
Skydan

0

Hemos abierto nuestra biblioteca de cliente REST asíncrona liviana para Android, puede resultarle útil si tiene requisitos mínimos y no desea manejar el subproceso múltiple usted mismo: está muy bien para comunicaciones básicas pero no para un cliente REST completo biblioteca.

Se llama libRESTfulClient y se puede encontrar en GitHub .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.