E para que esse resultado seja recebido e atualizado corretamente na
Activity , o
ResultReceiver que foi passado como parâmetro deve ser corretamente implementado:
Para quem quiser ter acesso ao código completo, o aplicativo exemplo desse post já está disponível no Github, como o projeto HttpIntentService .
Para saber mais
Alguns guias e tutoriais que podem ajudar a entender melhor os serviços e outros tópicos:
E no próximo post
E no próximo post vamos falar da biblioteca Volley, que facilita em muitos aspectos alguns dos passos apresentados nesse post. Essa biblioteca é mantida pelo Google e que ajuda na hora de realizar comunicação Web, possibilitando até a criação de uma fila de request e também abstrai vários aspectos da comunicação no seu aplicativo.
+Neto Marin
Android Developer Advocate
Olá pessoal,
Dando continuidade a série sobre comunicação web em apps Android (veja a parte I ), vamos abordar nesse post outras maneiras de se realizar requests HTTP e também algumas práticas em relação a utilização de serviços e comunicação entre serviços e activities.
Usando HttpURLConnection
No post anterior, o exemplo utilizado foi baseado na biblioteca Apache HttpClient, por considerar como uma biblioteca mais extensiva e também mais didática, quando apresentando os conceitos de GET e POST, pois possui objetos e classes separadas para ambas as ações.
Mas como podem ler no post Android’s HTTP Clients , se estiver escrevendo um app a partir da versão Froyo (2.2) é recomendado que utilize a classe HttpURLConnection .
Para maiores detalhes de como utilizar a o HttpURLConnection e suas configurações possíveis, há uma vasta documentação em nosso site oficial para desenvolvedores. Seguem alguns links:
Para uma referência rápida, segue abaixo um exemplo de como seria executado um simples GET, no mesmo endereço utilizado no código de demonstração do post anterior.
URL url = null;
HttpURLConnection con = null;
InputStream is = null;
try {
url = new URL("http://codigogdemos.appspot.com/simpleGetPost");
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.connect();
if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
is = con.getInputStream();
return getStringFromInputStream(is);
} else {
return null;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Esse foi um exemplo bem básico de como utilizar a HttpURLConnection , mas consultando a documentação é possível encontrar facilmente os métodos para configurar o método a ser executado ou como obter o OutputStream para envio de informações e até um arquivo todo. Além de ser possível encontrar vários exemplos e posts em blogs e também no Stackoverflow.
Comunicação Web e Services
Como falamos no post anterior, a regra de ouro é sempre executar as operações de rede fora da thread principal. O que nos levou ao exemplo de utilização da AsyncTask , e é o que normalmente leva a maioria dos desenvolvedores a fazerem a utilização do AsyncTask , diretamente de suas activities ou fragments.
E a pergunta que vem é, isso está certo?
Errado não está, mas não podemos considerar como uma das melhores práticas quando estamos falando de comunicação Web em apps Android. Isso porque o ideal é que nessas classes (Activity e Fragment ), fique apenas código relativo a interface com o usuário. Deve-se evitar ao máximo colocar código de lógica de negócio, persistência ou comunicação.
Uma das principais razões é organização e reúso de código. Mesmo que o código que faça a chamada de rede em si, esteja em uma classe separada, fazer todo o setup antes e depois fazer o tratamento das informações (parse, validação e etc) no código da Activity continua não sendo uma boa idéia. Até porque, você provavelmente vai ter as mesmas chamadas de diferentes pontos do seu aplicativo.
Uma prática muito utilizada, é realizar a parte de comunicação Web com Services . Assim, quando se deseja consumir/enviar algum dado, um serviço é inicializado e após a tarefa concluída ele notifica quem tiver feito a chamada, ou realiza um broadcast para avisar a todos os possíveis interessados.
Há varias maneiras de se fazer a comunicação entre o Service e quem fez a chamada, mas para o exemplo desse post, vamos utilizar um ResultReceiver . Também é possível deixar o parse e validação dos dados por conta de um Service (ou até o mesmo), que após realizar a persistência irá notificar a conclusão da tarefa.
E para o tratamento de requisições, pode-se utilizar um tipo específico de serviço, que é o IntentService . Assim é possível verificar se aquela request já está sendo executada ou também gerenciar um pool de requests. Isso é possível pois o IntentService trata suas chamadas de forma síncrona e em uma única instância.
Assim, por exemplo, após determinar se é realmente necessário iniciar uma nova request para a busca dos dados, isso pode ser feito utilizando uma nova Thread , liberando o IntentService para atender a próxima request.
Criando e executando um IntentService
Um IntentService é criado de forma muito parecida a de um serviço "convencional". A diferença é que na hora de definir no manifesto, não é necessário definir filtros para a Intent. Como ele vai ser chamado diretamente pela sua classe, não vai é necessário haver filtro.
Veja a declaração do HttpIntentService que foi criado para o exemplo desse post:
<service android:name=".HttpIntentService">
No exemplo, vamos passar uma frase para o serviço, que o enviará para um web service. Então, no código da Activity (ou Fragment ) não vamos ter nenhum código referente a lógica da conexão com rede ou tratamento da resposta. Veja o código para a chamada do serviço, quando o usuário aperta o botão para contar as palavras:
Intent serviceIntent = new Intent(this, HttpIntentService.class);
serviceIntent.putExtra(HttpIntentService.RESULT_RECEIVER_EXTRA,
resultReceiver);
serviceIntent.putExtra(HttpIntentService.STR_EXTRA_TEXT,
textEditText.getText().toString());
startService(serviceIntent);
Depois disso então, o HttpIntentService é chamado, e outra diferença é que ao invés de se sobrescrever os métodos onStartCommand() ou onBind() , o método com o qual você deve se preocupar é o onHandleIntent() .
Nesse exemplo, no onHandleIntent() vamos obter um texto que vai ser passado através da Intent e que deve ser enviado a um webservice para que o número de palavras nesse texto seja contado.
E para que o resultado seja retornado para a Activity que fez a chamada, vamos utilizar um ResultReceiver . Ele é criado na Activity e passado na Intent para o serviço, que após ter a resposta envia de volta através da mesma instância.
E para que esse resultado seja recebido e atualizado corretamente na Activity , o ResultReceiver que foi passado como parâmetro deve ser corretamente implementado:
Para quem quiser ter acesso ao código completo, o aplicativo exemplo desse post já está disponível no Github, como o projeto HttpIntentService .
Para saber mais
Alguns guias e tutoriais que podem ajudar a entender melhor os serviços e outros tópicos:
E no próximo post
E no próximo post vamos falar da biblioteca Volley, que facilita em muitos aspectos alguns dos passos apresentados nesse post. Essa biblioteca é mantida pelo Google e que ajuda na hora de realizar comunicação Web, possibilitando até a criação de uma fila de request e também abstrai vários aspectos da comunicação no seu aplicativo.
+Neto Marin
Android Developer Advocate