quarta-feira, 20 de novembro de 2013

Webservices

Olá à todos.

Em Android, não é complicado de obter dados da Internet. Neste tópico, mostraremos basicamente 2 exemplos de como conseguir isso: primeiramente, baixando um texto de uma URL da Internet; e por fim, obtendo dados de um webservice em formato JSON, de uma URL específica.

Obtendo uma informação simples da rede


Utilizaremos um exemplo bem simples para mostrar como baixar informações da rede. Em nosso exemplo, baixaremos o código-fonte de uma URL da Internet. Para isso, utilizaremos um layout com um botão, uma ProgressBar (uma View que sinaliza ao usuário que um processamento está sendo feito), e um TextView (onde colocaremos o código-fonte que acabamos de baixar).

Eis a representação deste layout:


Inicialmente, será mostrada apenas o botão “Load Webpage”. Ao clicarmos nele, será mudada a visibilidade da ProgressBar para Visible, e então começaremos a realizar o download do código-fonte da URL.

Uma vez realizado este download, a visibilidade da ProgressBar será mudada para Gone, e o conteúdo que baixamos da URL populará a TextView.

Basicamente é isto que nosso aplicativo de testes fará.

E eis o código-fonte da nossa tela principal:


Em nossa tela principal, temos nenhum método sendo chamando pelo evento onCreate().Porém, em nosso XML, temos a tag “onClick”, que  chama o método readWebpage(). Neste método, setamos a visibilidade da ProgressBar para Visible, e chamamos a DownloadWebPageTask, a AsyncTask que realiza o download da URL da Internet.

Nesta AsyncTask, no método doInBackground(), temos de fato o download do conteúdo da Internet. E no método onPostExecute() (que é chamado ao fim do download dos dados), a ProgressBar é ocultada, e o conteúdo da TextView é atualizado com o valor do código-fonte da URL baixada da Internet.

E é isso! Neste exemplo, conseguimos, de forma bem simplificada, obter dados da Internet.

Lendo dados de um webservice JSON 


O download de dados de um webservice JSON é um pouco mais complexo que o exemplo anterior. Utilizaremos como exemplo um aplicativo complementar ao aplicativo mostrado neste tópico do Blog. Porém, em nosso aplicativo, teremos também os pacotes api e utils.

No pacote api, temos 3 classes, que nos ajudarão na leitura do webservice JSON da Internet. Já no pacote utils, temos alguns métodos que auxiliam em tarefas básicas ao longo do nosso aplicativo. Por exemplo, o método StringUtils.isEmpty() verifica se uma String está vazia ou nula; já o método ActivityUtils.openActivity() chama uma Activity. E assim por diante.

O que importa estudarmos é o pacote api. Vamos à ele, então.

Neste pacote temos 3 classes:

  • ApiMapper Nesta classe convertemos o Object lido da Internet para uma List de nosso model. No caso do nosso aplicativo, nosso model é a classe Bean.java.
  • ApiRequest Nesta classe, obtemos o Object lido da Internet, e, chamando a classe ApiMapper, o convertemos para uma List de model.
  • OperationResult Nesta classe verificamos, detalhadamente, se o download dos dados da Internet foi realizado corretamente (verificando 14 status diferentes), e também montamos a estrutura de retorno destes dados, através de métodos como getEntityList() e setEntityList(), que obtém e inicializam listas do model que mapeamos o Object advindo da Internet.


A parte mais importante da classe ApiMapper é mostrada abaixo:


Nela, podemos ver claramente como um dado é mapeado para nosso model de Bean. Os métodos getInt() e getString() (que basicamente fazem cast de tipos) são mostrados abaixo:


E o método data.get() é um método básico do tipo Map. Um Map associa uma chave à um dado. Neste caso, a chave é Bean.KEY_ID e Bean.KEY_NAME, e o dado é o valor advindo do webservice. Para entender bem isso, basta darmos uma olhada em nosso webservice em JSON:


Repare que temos os campos “id” e “nome”. Repare agora, abaixo, o valor das constantes Bean.KEY_ID e Bean.KEY_NAME, advindos da classe Bean.java, do pacote model:


Logo, o método data.get() faz a comparação entre o nome dos campos do webservice em JSON, e o nome das constante do nosso model. Uma vez encontrando uma correspondência, joga os dados do webservice em nossa variável data.

Já a parte mais importante da classe ApiRequest é a mostrada abaixo:


Inicialmente, no método getBeanList(), vemos que é montada a String url que nada mais é do que a URL de origem dos dados do webservice.

Então, é feita uma tentativa de se obter os dados da Internet, através do método executeHttpGetWithRetry(). Como a obtenção destes dados está sujeita a erros, o executamos dentro da cláusula try.

Repare que este método é um método da classe HttpManager, constante no pacote manager. Caso alguém queira dar uma olhada nesta classe, sinta-se à vontade. Porém, sua implementação é tão complexa que julgo ser desnecessário explicá-la em detalhes. Tudo que precisamos saber dela é que ela recebe como parâmetro uma URL, e, em caso de sucesso, retorna o conteúdo desta URL (em String), ou, caso contrário, retorna um dos tipos de retorno de status de uma requisição HTTP, conforme explicado no link http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Há de se salientar também que a classe HttpManager implementa o padrão Singleton, analogamente à nossa já conhecida classe ContentManager.

Continuando à explicação sobre o método getBeanList() da classe ApiRequest, logo após a execução do método executeHttpGetWithRetry(), temos a verificação do retorno do webservice, checando se ocorreram erros no retorno dos dados da Internet:


Caso tenham ocorrido erros, o método é finalizado. Caso não, seguimos no fluxo da nossa aplicação.

Em sequência (caso não tenham ocorrido erros que fecharam nosso método), temos a obtenção dos dados do webservice, através do método getResponseString(). Caso ele não seja vazio, seguimos o fluxo do nosso método:


Então, finalmente, realizamos a conversão dos dados do webservice para nosso model:


Tal conversão é realizada, basicamente, através de checagens de tipo Map (como explicado anteriormente, neste tópico).

Repare também que são verificadas várias exceções. Logo, com tantas verificações acerca dos dados do webservice, o método proposto neste tópico se caracteriza como um método bastante confiável.

Por fim, temos a classe OperationResult. Nela temos o mapeamento dos tipos de retorno de código de webservice (como o código 200, “Ok”; e o código 404, ”Not Found”), e também o retorno do OperationResult caso os dados tenham sido baixados sem problemas.

Dentre estes retornos, temos setEntity() e setEntityList(), e seus respectivos getters. O método setEntity() atribui à um OperationResult um dado, e apenas um dado, de um tipo específico. Já o método setEntityList() atribui uma lista à um OperationResult.

Todos estes métodos são utilizados principalmente pela classe BeanAsyncTask, que é a classe responsável pela obtenção dos dados, seja do banco de dados, seja do webservice. Ela já foi explicada anteriormente neste tópico do blog.

Sobre essa classe, mostraremos abaixo os métodos update() e getBeanFromServer(), que foram atualizados, e agora fazem uso de webservices:


Podemos notar acima que o método getBeanFromServer() é chamado. O que ele faz? Veremos abaixo:


Este é o método que, de fato, interage com o webservice, chamando o método ApiRequest.getBeanList(). Caso haja sucesso na obtenção do webservice, além se setarmos o seu resultado no OperationResult através do método setEntityList(), salvamos os dados no banco de dados, através do método persistBean() (que está dentro de uma thread, uma vez que salvar dados em um banco podem demorar além do previsto).

-----

E é isto. Agora já estamos aptos a criar aplicações que obtenham dados de um webservice.

Caso alguém tenha uma dúvida, crítica ou sugestão, sinta-se à vontade.

Nenhum comentário:

Postar um comentário