Imprimir este capítuloImprimir este capítulo

Livro 4 - Projeto da Previsão do Tempo

2. Recursos Envolvidos

Nesse projeto usaremos os seguintes recursos na construção do aplicativo WeatherApp:

  • Web Services 
    • Um web service é um tipo de servidor hospedado na rede (internet) que recebe pedidos de clientes (por exemplo, o aplicativo WeatherApp), os processa e retorna uma resposta pela rede.
    • Através desse serviço, um aplicativo pode acessar dados sob demanda em vez de armazená-los diretamente no dispositivo ou fazer acesso a um banco de dados externo. Da mesma forma, um aplicativo que não tenha poder de processamento para efetuar cálculos específicos poderia usar um web servisse para usufruir dos recursos superiores de outro sistema.

  • Web Service REST
    • REST (Representation State Transfer) se refere ao estilo arquitetônico para implementar web services – também podem ser chamados de web services RESTful. Muitos dos web services mais populares da atualidade, gratuitos e pagos, são RESTful.
    • Essa arquitetura faz normalmente o uso do protocolo HTTP (HyperText Transfer Protocol) usado pelos navegadores web. Assim, cada método de um web service RESTful é identificado por uma URL exclusiva. Quando o servidor recebe uma solicitação, ele sabe imediatamente qual operação executar.
    • Quais operações podem ser feitas, bem como os parâmetros que podem ser especificados, estão documentos na API (Aplication Programming Interface) de cada web service. Algumas API´s populares: Google Maps, Facebook, Twitter, Youtube, OpenWeatherMap e LinkdIn.
    • Para fazer o uso do web service frequentemente é exigido uma chave de API. Essa chave é usada para identificar o cliente (aplicativo ou usuário) e serve para confirmar a permissão de uso ao serviço e também monitorar o seu uso. Normalmente, chaves gratuitas possuem limitações como 50 acessos por segundo e podem ser usadas para aplicativos pequenos como no caso do WeatherApp. Se seu aplicativo fosse para distribuição comercial, provavelmente os números de acessos cresceria e você teria que pagar por uma chave para continuar usando o serviço.
  • Web Service da OpenWeatherMap.org
    • Os serviços da OpenWeatherMap API utilizados neste projeto usarão uma chave de API gratuita disponibilizada neste documento. Caso você queria criar uma conta pessoal e usar uma chave própria, realize o registro no site oficial da API:

    • Para obter mais informações sobre os planos do serviço e seu custo, acesso o link:

    • Neste aplicativo iremos usar a API “Call 5 day / 3 hour forecast data” para obter os dados da previsão do tempo de uma cidade específica. Basicamente, precisamos usar a URL: api.openweathermap.org/data/2.5/forecast?q= informando o nome da cidade e campos opcionais (especificamente, números de dias, padrão de medidas e idioma). Para mais informações sobre a API acesso o link:

    • Para mais informações sobre os serviços disponibilizados pela OpenWeatherMap acesso o link a seguir. Note que alguns serviços só estarão disponíveis para chaves pagas:

    • Para obter mais informações sobre os termos de serviço acesse o primeiro link a seguir. Ademais, a OpenWeatherMap usa uma licença Creative Commons pública para serviços e pode ser acessada no segundo link abaixo.

  • JSON
    • JSON (JavaScript Object Notation) é um formato de representação de dados baseado em texto, utilizado para representar objetos em JavaScript, como coleções de pares nome/valor. Devido a facilidade de criar, ler e analisar objetos no formato JSON, diversos serviços web optam por usar essa representação ao invés do padrão XML.

{

   nome: “Fulano”

   idade: 23

   disciplinas: [ “Português”, “Matemática”, “Química”]

   endereco: {

      cidade: Jaraguá do Sul

      cep: 98392-239

   }

}

  

    • Cada objeto JSON é representado como uma lista de nomes e valores de propriedades contidas em chaves, como exemplificado acima. Cada nome da propriedade é uma String e o valor de cada chave pode ser um número, texto, array (lista de valores) ou outro objeto JSON. No caso de arrays, usamos os colchetes para identificar a lista de valores, e no caso dos JSON usamos novamente as chaves.
    • Alguns web services, como no caso da OpenWeatherMap, oferecem a opção de resposta tanto em JSON quanto XML. Neste projeto optaremos pela primeira opção. Dessa forma, uma solicitação a API deve retornar algo do tipo:

{

    "cod": "200",

    "message": 0.0047,

    "cnt": 2,

    "list": [

        {

            "dt": 1525370400,

            "main": {

                "temp": 300.95,

                "temp_min": 297.369,

                "temp_max": 300.95,

                "pressure": 968.34,

                "sea_level": 1029.33,

                "grnd_level": 968.34,

                "humidity": 84,

                "temp_kf": 3.58

            },

            "weather": [

                {

                    "id": 500,

                    "main": "Rain",

                    "description": "light rain",

                    "icon": "10d"

                }

            ],

            "clouds": {

                "all": 24

            },

            "wind": {

                "speed": 0.41,

                "deg": 21.5013

            },

            "rain": {

                "3h": 0.24

            },

            "sys": {

                "pod": "d"

            },

            "dt_txt": "2018-05-03 18:00:00"

        },

        {

            "dt": 1525381200,

            "main": {

                "temp": 296.36,

                "temp_min": 293.975,

                "temp_max": 296.36,

                "pressure": 968.72,

                "sea_level": 1029.83,

                "grnd_level": 968.72,

                "humidity": 97,

                "temp_kf": 2.39

            },

            "weather": [

                {

                    "id": 500,

                    "main": "Rain",

                    "description": "light rain",

                    "icon": "10n"

                }

            ],

            "clouds": {

                "all": 20

            },

            "wind": {

                "speed": 1.01,

                "deg": 12.0102

            },

            "rain": {

                "3h": 0.165

            },

            "sys": {

                "pod": "n"

            },

            "dt_txt": "2018-05-03 21:00:00"

        }

    ],

    "city": {

        "id": 3460102,

        "name": "Jaraguá do Sul",

        "coord": {

            "lat": -26.4898,

            "lon": -49.0779

        },

        "country": "BR",

        "population": 130130

    }

}

    • No objeto JSON retornado acima, há muitas propriedades. Neste projeto iremos usar apenas a propriedade “list”. Essa propriedade retorna uma lista com a previsão a cada 3h para até 5 dias. Enfim, cada elemento do array “list” possui os campos:

      • dt” – um inteiro long, contém o carimbo de data/hora (timestamp) representando o número de segundos desde 1º de janeiro de 1970, GMT. Usamos essa informação para obter o nome do dia.

      • "main” – um objeto JSON contendo as propriedades double das temperaturas mínima (“temp_min”) e máxima (“temp_max”). Também vamos usar a umidade (“humidity”) representada como um inteiro.

      • weather” – um objeto JSON contendo as informações da condição climática. Vamos usar a descrição da condição (“description”) e o nome do ícone que as representa (“icon”)

  • Pacote org.json
    • Vamos usar as seguintes classes do pacote org.json para processar os dados JSON recebidos pelo aplicativo.
    • JSONObject – Um dos construtores dessa classe converte uma String, escrita nos padrões JSON, em um JSONObject. Esse objeto contém um Map<String, Object> para mapear as propriedades aos respectivos valores. Os valores associados a cada campo podem ser do tipo int, long, double, boolean, String, JSONObject e JSONArray. Através dos métodos get e set desse objeto, conseguimos fazer acesso as propriedades.

    • JSONArray – essa classe representa um array de JSON e fornece métodos para acessas seus elementos. A propriedade “list” na resposta da OpenWeatherMap API será manipulada como um JSONArray.

  • Classe HttpUrlConnection e comunicação com um web service REST

    • Para ativar serviço web vamos precisar fazer uma solicitação HTTP para a API. Essa tarefa é alcançada no Java com a classe HttpUrlConnection, presente no pacote java.net. Através de uma String representando uma URL, vamos criar um objeto URL para abrir uma nova HttpUrlConnection. Essa conexão fará a solicitação HTTP e receberá como resposta um objeto JSON. A leitura dos dados de resposta é feita com o uso de uma classe InputStream que recebe linha por linha, string por string, o conteúdo do objeto JSON. Vamos converter os dados lidos em um JSONObject para processamento.

  • AsyncTask
    • A comunicação a um serviço externo (leitura de arquivos, banco de dados, serviço web) pode ser uma operação longa ou até mesmo bloquear a execução do aplicativo. Portanto, essas operações devem ser realizadas fora da thread principal do aplicativo. Isso ajuda a manter a velocidade de resposta do aplicativo e evita caixas de diálogo Activity Not Responding (ANR), que aparecem quando o Android detecta que a interface gráfica não está respondendo.

    • Para executar tarefas em paralelo o Android disponibiliza a classe AsyncTask (pacote android.os), a qual executa operações de longa duração em uma thread separada e transmite os resultados para a thread principal. Neste aplicativo, vamos usar duas subclasses de AsyncTask: uma para ativar o serviço web e fazer as solicitações HTTP; e outra para baixar uma imagem de condição climática.
  • ListView, ArrayAdapter e Padrão ViewHolder
    • Este aplicativo exibe os dados climáticos em um componente ListView. Para preencher essa lista vamos precisar criar uma subclasse de ArrayAdapter, cuja finalidade é preencher o elemento ListView utilizando dados de um objeto ArrayList.
    • Quando o aplicativo adicionar os dados climáticos ao ArrayList, vamos chamar o método notifyDataSetChanged de ArrayAdapter para indicar que os dados mudaram. Então, o adaptador notificará o componente ListView para que atualize sua lista de itens exibidos. Isso é conhecido como vinculação de dados (data biding).
    • Cada item adicionado a lista envolve a execução do processo de criar novos objetos dinamicamente. Para listas grandes, nos quais o usuário rola rapidamente, a quantidade de itens gera uma sobrecarga que pode impedir uma rolagem suave. Logo, para reduzir essa sobrecarga, quando os itens do componente ListView rolam para fora da tela, vamos fazer a reutilização desses itens de lista para os novos que estão entrando na tela. Para isso, usamos o padrão ViewHolder, no qual criamos uma classe (normalmente chamada ViewHolder) para conter variáveis de instância para as views que exibem os dados dos itens na ListView.

    • Para cada item da lista, adicionamos também um novo objeto ViewHolder a view através do método setTag. Assim, quando um novo item está a ponto de rolar para fora da tela, o elemento ListView verifica se existe uma view reutilizável. Se não tiver, cria um novo item. Mas se tiver, ele usa o método getTag para obter o objeto ViewHolder e substituir o valor dos seus campos.
  • FloatingActionButton

    • Os botões de ação flutuantes, mais comumente chamados de FAB (FloatingActionButton), foram introduzidos pelo Material Design e são botões que “flutuam”, isto é, possuem elevação maior que o restante dos elementos da interface gráfica do aplicativo. A partir do Android 6.0, esse componente passou a ser disponibilizado pela Android Design Support Library

    • É comum usar esse botão para uma ação única, mas importante para o aplicativo. Alguns exemplos de seu uso: enviar um email (Gmail) , adicionar um contato (Projeto 3) e, no caso da WeatherApp, submeter a busca das condições climáticas de uma cidade.

    • FloatingActionButton é uma subclasse de ImageView, portanto, é possível usar esse botão para exibir uma imagem. Dessa forma, podemos adicionar ícones do Material Design e usar nos FAB’s.

    • As diretrizes do Material Design sugerem posicionar esses botões a pelo menos 16dp das margens do celular e a pelo menos 24dp das margens em um tablet. Naturalmente, o Android Studio configura esses valores padrões aos botões do projeto, mas nada impede de modifica-los.

  • TextInputLayout

    • Os componentes EditText são usados para criar caixas de texto de modo que o usuário possa digitar algum conteúdo. Para ajudar o usuário entender a finalidade da caixa de texto, podemos especificar a propriedade hint (dica) para esse elemento. Isso mostrará uma mensagem dentro da caixa de texto que desaparecerá assim que o usuário começar a digitar o texto. Por causa disso, pode acontecer do usuário esquecer da finalidade do elemento EditText, uma vez que a dica não aparecerá novamente. Para evitar isso, usamos TextInputLayout (pacote android.support.design.widget) da Android Design Support Library.

    • Em um TextInputLayout, quando o elemento EditText recebe foco, o TextInputLayout anima o texto da dica, mudando seu tamanho original para um menor e exibe-o acima da caixa de texto. Desse modo, o usuário pode digitar os dados e ver a dica ao mesmo tempo.

  • Snackbar
    • Snackbar (pacote android.support.design.widget) é um componente Material Design conceitualmente semelhante a um Toast. Além de aparecer na tela por um limite de tempo especificado, os componentes Snackbar também são interativos. Os usuários podem passar o dedo rapidamente por eles para removê-los. Um componente Snackbar também tem uma ação associada para executar quando o usuário toca nele. Nesse aplicativo, vamos usar um componentes Snackbar para exibir mensagens informativas.