Cliente REST Android, amostra?

115

Mesmo que este tópico tenha uma resposta aceita, fique à vontade para propor outras ideias, você usa ou gosta


Conheci estes artigos:

E isso me levou a este vídeo do Google I / O 2010 sobre aplicativos clientes REST

Desde agora, tenho criado o componente REST como um componente estático na minha classe de controlador de aplicativo.

A partir de agora, acho que devo mudar o padrão. Alguém apontou que o aplicativo Google IOSched é um ótimo exemplo de como escrever clientes REST no Android. Outra pessoa disse que esse método é muito complicado.

Então, alguém pode nos mostrar qual é a melhor prática? De forma curta e simples.
O aplicativo IOSched é muito complexo para o caso de uso de amostra.

Marek Sebera
fonte
Olá, Geralmente eu desenvolvo um pacote separado para serviço da web chamado "ws", generalizo a classe chamada "WebServicUtils.java". A classe WebServiceUtils.java possui métodos para acessar o serviço da web. Não tenho certeza se minha técnica é a melhor ou não, mas é reutilizável toda vez que copio meu pacote ws no aplicativo Android, me avise se quiser saber mais sobre minha técnica.
Ketan Parmar
Não acho que o comentarista do YouTube tenha uma alternativa melhor. Temos que trabalhar dentro das APIs do Android, mesmo que sejam muitas vezes absurdamente complicadas e prolixas.
Timmmm
Como observação lateral, o Mechanoid, um plug-in eclipse de código aberto para Android, pode gerar clientes JSON-REST usando uma DSL simples. Um guia sobre como usá-lo pode ser encontrado aqui robotoworks.com/mechanoid-plugin/service-client-dsl (Eu sou o autor deste plug-in, desculpe pelo plug-in vergonhoso!)
Ian Warwick
Isso pode ser muito útil para quem está aprendendo a implementação do cliente REST do Android. Apresentação de Dobjanschi transcrita em PDF: drive.google.com/file/d/0B2dn_3573C3RdlVpU2JBWXdSb3c/…
Kay Zed

Respostas:

99

EDIT 2 (outubro de 2017):

Estamos em 2017. Basta usar Retrofit. Quase não há razão para usar qualquer outra coisa.

EDITAR:

A resposta original tinha mais de um ano e meio na época desta edição. Embora os conceitos apresentados na resposta original ainda sejam válidos, como outras respostas apontam, agora existem bibliotecas que tornam essa tarefa mais fácil para você. Mais importante, algumas dessas bibliotecas tratam das mudanças de configuração do dispositivo para você.

A resposta original é mantida abaixo para referência. Mas também reserve um tempo para examinar algumas das bibliotecas cliente Rest para Android para ver se elas se encaixam nos seus casos de uso. A seguir está uma lista de algumas das bibliotecas que avaliei. Não tem a intenção de ser uma lista exaustiva.


Resposta Original:

Apresentando minha abordagem para ter clientes REST no Android. Eu não afirmo que seja o melhor :) Além disso, observe que foi isso que eu criei em resposta à minha solicitação. Pode ser necessário ter mais camadas / adicionar mais complexidade se o seu caso de uso exigir. Por exemplo, eu não tenho armazenamento local; porque meu aplicativo pode tolerar a perda de algumas respostas REST.

Minha abordagem usa apenas AsyncTasks nos bastidores. No meu caso, eu "chamo" essas tarefas da minha Activityinstância; mas para levar em conta casos como rotação de tela, você pode escolher chamá-los de um Serviceou outro.

Eu escolhi conscientemente meu próprio cliente REST para ser uma API. Isso significa que o aplicativo que usa meu cliente REST nem precisa estar ciente da URL REST real e do formato de dados usado.

O cliente teria 2 camadas:

  1. Camada superior: o objetivo desta camada é fornecer métodos que espelham a funcionalidade da API REST. Por exemplo, você poderia ter um método Java correspondente a cada URL em sua API REST (ou mesmo dois - um para GETs e um para POSTs).
    Este é o ponto de entrada para a API do cliente REST. Esta é a camada que o aplicativo usaria normalmente. Pode ser um singleton, mas não necessariamente.
    A resposta da chamada REST é analisada por esta camada em um POJO e retornada ao aplicativo.

  2. Esta é a AsyncTaskcamada de nível inferior , que usa métodos de cliente HTTP para realmente sair e fazer a chamada REST.

Além disso, optei por usar um mecanismo de retorno de chamada para comunicar o resultado do AsyncTasks de volta ao aplicativo.

Chega de texto. Vamos ver alguns códigos agora. Vamos pegar um URL de API REST hipotético - http://myhypotheticalapi.com/user/profile

A camada superior pode ter esta aparência:

   /**
 * 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();

}

Observe que o aplicativo não usa o JSON ou XML (ou qualquer outro formato) retornado pela API REST diretamente. Em vez disso, o aplicativo vê apenas o bean Profile.

Então, a camada inferior (camada AsyncTask) pode ter a seguinte aparência:

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

Veja como um aplicativo pode usar a API (em um Activityou 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 os comentários sejam suficientes para explicar o design; mas ficaria feliz em fornecer mais informações.

curioustechizen
fonte
Eu gosto mais dessa resposta devido aos exemplos de código muito bom. Obrigado
Marek Sebera
1
Provavelmente não vale nada, isso realmente não segue um padrão MVC RESTful adequado, conforme descrito por Virgil Dobjanschi. Você precisaria incorporar uma camada ContentProvider completa, que usa um banco de dados SQLite que o aplicativo usa diretamente. Caso contrário, este é um cliente REST leve e bom para Android.
Cooper
1
Uma pequena coisa, você precisará chamar execute naqueles Get / PostTask's
Mo Kargas
1
Isso é realmente ótimo. Como eu tornaria o GetResponseCallback mais genérico, para que ele não passasse apenas um Perfil de volta, ou você sugeriria fazer um GetResponseCallback separado para cada tipo de dados da API?
1
@MichaelHerbig Sim, existem maneiras de torná-lo GetResponseCallbackmais genérico. O que eu prefiro é usar uma interface de marcador : Gosto interface IGetResopnse{} de denotar todas as classes que podem ser respostas. Então, eu tenho class Profile implements IGetResponseetc. Finalmente, fazer GetResponseCallbackgenérico com IGetResponseque o limite superior : public abstract class GetResponseCallback<? extends IGetResponse>.
curioustechizen
11

"Desenvolvendo aplicativos cliente REST para Android", de Virgil Dobjanschi, gerou muita discussão, já que nenhum código-fonte foi apresentado durante a sessão ou foi fornecido posteriormente.

A única implementação de referência que conheço (por favor, comente se souber mais) está disponível em Datadroid (a sessão Google IO é mencionada em / apresentação). É uma biblioteca que você pode usar em seu próprio aplicativo.

O segundo link pede a "melhor" estrutura REST, que é amplamente discutida no stackoverflow. Para mim, o tamanho do aplicativo é importante, seguido pelo desempenho da implementação.

  • Normalmente eu uso a implementação org.json simples, que faz parte do Android desde o nível 1 da API e, portanto, não aumenta o tamanho do aplicativo.
  • Para mim, foram muito interessantes as informações encontradas sobre o desempenho dos analisadores JSON nos comentários: a partir do Android 3.0 Honeycomb, o analisador de streaming do GSON é incluído como android.util.JsonReader. Infelizmente, os comentários não estão mais disponíveis.
  • Spring Android (que eu uso às vezes) oferece suporte a Jackson e GSON. A documentação do Spring Android RestTemplate Module aponta para um aplicativo de amostra .

Portanto, prefiro org.json ou GSON para cenários mais complexos. Para a arquitetura de uma implementação org.json, estou usando uma classe estática que representa os casos de uso do servidor (por exemplo, findPerson, getPerson). Eu chamo essa funcionalidade de um serviço e uso classes de utilitário que estão fazendo o mapeamento (específico do projeto) e o IO de rede (meu próprio modelo REST para GET ou POST simples). Tento evitar o uso de reflexão.

ChrLipp
fonte
4
O livro da O'Reilly, Programming Android, apresenta uma implementação completa do padrão RESTful MVC de Dobjanschi (capítulos 12-13).
Cooper de
Obrigado pela dica: encontrei esta declaração na Amazon: "Os capítulos 12 e 13 tratam de provedores de conteúdo. O tratamento extensivo dos provedores de conteúdo com código de exemplo e um aplicativo de exemplo me forneceu vários novos insights sobre como essa tecnologia funciona e como ela pode ser usado em situações reais de programação. A estrutura do provedor de conteúdo para armazenar e referenciar dados usando URIs é um dos novos recursos do sistema operacional Android. Excelente trabalho explicando a tecnologia passo a passo! "
ChrLipp de
2
O código está em github.com/bmeike/ProgrammingAndroid2Examples (mas faltam capítulos, você pode encontrá-los no código da primeira edição github.com/bmeike/ProgrammingAndroidExamples )
ChrLipp
Alguém conseguiu fazer esse código rodar no ICS +? O arquivo todo no exemplo FinchVideo afirma sucintamente "- Crashes under ICS". Fiquei um tanto desapontado depois de comprar o livro para descobrir que os exemplos de código estão corrompidos ...
ansioso analista
7

Nunca use AsynTask para realizar solicitações de rede ou qualquer coisa que precise ser persistida. As tarefas assíncronas estão fortemente ligadas à sua atividade e se o usuário alterar a orientação da tela desde que o aplicativo foi recriado, a tarefa Async será interrompida.

Eu sugiro que você use o padrão de serviço com Intent Service e ResultReceiver. Dê uma olhada em RESTDroid . É uma biblioteca que permite realizar qualquer tipo de solicitação REST de forma assíncrona e notificar sua IU com Ouvintes de Solicitação implementando o padrão de serviço de Virgil Dobjanschi.

Pierre Criulanscy
fonte
3

Há outra biblioteca com API muito mais limpa e dados seguros para tipos. https://github.com/kodart/Httpzoid

Aqui está um exemplo de uso simples

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

Ou mais complexo com callbacks

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

É novo, mas parece muito promissor.

Arthur
fonte
Parece estar executando em AsyncTask, o que não é bom para solicitações de longa duração e alterna entre atividades, porque AsyncTask será encerrado quando a atividade for encerrada.
Malachiasz
1

Há muitas bibliotecas por aí e estou usando esta: https://github.com/nerde/rest-resource . Este foi criado por mim e, como podem ver na documentação, é muito mais limpo e simples que os outros. Não está focado no Android, mas estou usando e está funcionando muito bem.

Suporta HTTP Basic Auth. Ele faz o trabalho sujo de serializar e desserializar objetos JSON. Você vai gostar, principalmente se sua API for como Rails.

Diego
fonte
1

Isenção de responsabilidade: estou envolvido no projeto de código aberto rest2mobile

Outra alternativa como cliente REST é usar o rest2mobile .

A abordagem é um pouco diferente, pois usa exemplos de resto concretos para gerar o código do cliente para o serviço REST. O código substitui a URL REST e as cargas úteis JSON por métodos nativos de java e POJOs. Ele também lida automaticamente com conexões de servidor, invocações assíncronas e POJO de / para conversões JSON.

Observe que esta ferramenta vem em diferentes sabores (cli, plugins, suporte para android / ios / js) e você pode usar o plug - in do android studio para gerar a API diretamente em seu aplicativo.

Todo o código pode ser encontrado no github aqui .

Manu
fonte
3
Substitua o primeiro link pelo destino real em vez de anunciar seu site.
Skydan
0

Abrimos o código-fonte de nossa biblioteca cliente REST assíncrona leve para Android, você pode achar útil se tiver requisitos mínimos e não quiser lidar com o multithreading sozinho - é muito bom para comunicações básicas, mas não um cliente REST completo biblioteca.

É chamado de libRESTfulClient e pode ser encontrado no GitHub .

bk138
fonte