Crear una aplicación de clima en Android

Lo que vas a crear

Muchas de las aplicaciones meteorológicas populares en Google Play están llenas de anuncios, requieren demasiados permisos o incluyen características que la mayoría de nosotros nunca usamos. ¿No sería genial si pudieras construir tu propia aplicación meteorológica desde cero??

En este tutorial, te voy a mostrar cómo. Nuestra aplicación tendrá una interfaz de usuario simple y minimalista, que muestra al usuario exactamente lo que necesita saber sobre las condiciones climáticas actuales. Empecemos.

Buscando un atajo?

Este tutorial te enseñará a crear una aplicación meteorológica desde cero, pero una alternativa es utilizar una de las plantillas de aplicaciones meteorológicas de Android en Envato Market..

Por ejemplo, Weminder proporciona una interfaz de usuario sencilla y limpia y todas las características esenciales de una aplicación meteorológica, para que luego pueda personalizarla para sus propios fines..

Plantilla de aplicación del tiempo Weminder en Envato Market

O, si desea algo único y personalizado, diríjase a Envato Studio para ver la selección de servicios móviles y de desarrollo de aplicaciones que se ofrecen allí..

1. Requisitos previos

Antes de continuar, compruebe que tiene la siguiente configuración:

  • Eclipse ADT Bundle: Puedes descargarlo en el sitio web de Android Developer..
  • OpenWeatherMap Clave API : Esto no es necesario para completar el tutorial, pero es gratis. Puede obtener uno al registrarse en el sitio web de OpenWeatherMap.
  • Iconos: Te recomiendo que descargues la fuente de los iconos del tiempo creada por Erik Flowers. Debe descargar el archivo TTF, porque lo usaremos en una aplicación nativa. Usaremos la fuente para renderizar varios iconos dependiendo de las condiciones climáticas.

2. Crear un nuevo proyecto

Voy a llamar a esta aplicación SimpleWeather, Pero siéntete libre de darle el nombre que quieras. Ingrese un nombre de paquete único, establezca el SDK mínimo requerido en Android 2.2, y establece el SDK de destino en Android 4.4. Puedes dejar el tema en Holo Dark.

Esta aplicación solo tendrá una Actividad y se basará en el Actividad en blanco plantilla como se muestra a continuación.

Nombra el Actividad TiempoActividad. Estaremos usando un Fragmento dentro de este Actividad. El diseño asociado a la Actividad es activity_weather.xml. El diseño asociado a la Fragmento es fragment_weather.xml.

3. Añadir la fuente personalizada

Dupdo weathericons-regular-webfont.ttf a tu proyecto activos / fuentes directorio y renombrarlo a weather.ttf.

4. Edita el Manifiesto

El único permiso que necesita esta aplicación es android.permission.INTERNET.


Para mantener este tutorial simple, solo vamos a apoyar retrato modo. los actividad El nodo del manifiesto debe verse así:

     

5. Edita el diseño de la actividad

No hay mucho que cambiar en activity_weather.xml. Ya debería tener un FrameLayout. Agrega una propiedad extra para cambiar el color de la fondo a # FF0099CC.

 

6. Edita el diseño del fragmento

Editar fragment_weather.xml añadiendo cinco Vista de texto Etiquetas para mostrar la siguiente información:

  • ciudad y país
  • temperatura actual
  • un icono que muestra las condiciones meteorológicas actuales
  • una marca de tiempo que indica al usuario cuándo se actualizó por última vez la información meteorológica
  • Información más detallada sobre el clima actual, como la descripción y la humedad.

Utilizar una Disposición relativa para organizar las vistas de texto. Puedes ajustar el tamano del texto para adaptarse a varios dispositivos.

       

7. Editar cadenas.xml

Este archivo contiene las cadenas utilizadas en nuestra aplicación, así como los códigos de caracteres de Unicode que usaremos para representar los iconos del tiempo. La aplicación podrá mostrar ocho tipos diferentes de condiciones climáticas. Si desea manejar más, consulte esta hoja de trucos. Agregue lo siguiente a valores / cadenas.xml:

  Clima simple Cambiar ciudad  11111 & # xf00d; & # xf02e; & # xf014; & # xf013; & # xf019; & # xf01b; & # xf01e; & # xf01c; Lo sentimos, no se han encontrado datos meteorológicos. 

8. Añadir un elemento de menú

El usuario debe poder elegir la ciudad cuyo clima desea ver. Editar menu / weather.xml y agregar un elemento para esta opción.

  

Ahora que todos los archivos XML están listos para usar, avancemos y consultemos la API de OpenWeatherMap para obtener datos meteorológicos.

9. Obtener datos de OpenWeatherMap

Podemos obtener los detalles meteorológicos actuales de cualquier ciudad formateada como JSON utilizando la API OpenWeatherMap. En la cadena de consulta, pasamos el nombre de la ciudad y el sistema métrico en el que deben aparecer los resultados..

Por ejemplo, para obtener la información meteorológica actual de Canberra, mediante el sistema métrico, enviamos una solicitud a http://api.openweathermap.org/data/2.5/weather?q=Canberra&units=metric

La respuesta que recibimos de la API se ve así:

"base": "estaciones de cmc", "nubes": "todas": 90, "cod": 200, "coord": "lat": -35.28, "lon": 149.13, "dt" : 1404390600, "id": 2172517, "main": "humedad": 100, "pressure": 1023, "temp": -1, "temp_max": -1, "temp_min": -1, "name ":" Canberra "," sys ": " country ":" AU "," message ": 0.313," sunrise ": 1404335563," sunset ": 1404370965," weather ": [" description ":" overcast nubes "," icono ":" 04n "," id ": 804," main ":" Clouds "]," wind ": " deg ": 305.004," speed ": 1.07

Crear una nueva clase de Java y nombrarla RemoteFetch.java. Esta clase es responsable de obtener los datos del clima de la API de OpenWeatherMap.

Usamos el HttpURLConnection Clase para realizar la solicitud remota. La API de OpenWeatherMap espera la clave de la API en un encabezado HTTP llamado x-api-key. Esto se especifica en nuestra solicitud utilizando el setRequestProperty método.

Usamos un BufferedReader para leer la respuesta de la API en una StringBuffer. Cuando tenemos la respuesta completa, la convertimos a un JSONObject objeto.

Como puede ver en la respuesta anterior, los datos JSON contienen un campo llamado bacalao. Su valor es 200 si la solicitud fue exitosa Usamos este valor para verificar si la respuesta JSON tiene la información del clima actual o no.

los RemoteFetch.java La clase debería verse así:

paquete ah.hathi.simpleweather; importar java.io.BufferedReader; importar java.io.InputStreamReader; importar java.net.HttpURLConnection; import java.net.URL; importar org.json.JSONObject; importar android.content.Context; import android.util.Log; clase pública RemoteFetch String final privada estática OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; público JSONObject estático getJSON (contexto de contexto, ciudad de cadena) try URL url = new URL (String.format (OPEN_WEATHER_MAP_API, ciudad)); Conexión HttpURLConnection = (HttpURLConnection) url.openConnection (); connection.addRequestProperty ("x-api-key", context.getString (R.string.open_weather_maps_app_id)); BufferedReader reader = new BufferedReader (new InputStreamReader (connection.getInputStream ())); StringBuffer json = new StringBuffer (1024); Cuerda; while ((tmp = reader.readLine ())! = null) json.append (tmp) .append ("\ n"); reader.close (); Datos JSONObject = nuevo JSONObject (json.toString ()); // Este valor será 404 si la solicitud no fue satisfactoria // si (data.getInt ("cod")! = 200) return null;  datos de retorno;  catch (Exception e) return null; 

10. Almacenar la ciudad como una preferencia

El usuario no debería tener que especificar el nombre de la ciudad cada vez que quiera usar la aplicación. La aplicación debe recordar la última ciudad en la que estaba interesado el usuario. Hacemos esto haciendo uso de Preferencias compartidas. Sin embargo, en lugar de acceder directamente a estas preferencias desde nuestro Actividad clase, es mejor crear una clase separada para este propósito.

Crear una nueva clase de Java y nombrarla CityPreference.java. Para almacenar y recuperar el nombre de la ciudad, cree dos métodos setCity y getCity. los Preferencias compartidas El objeto se inicializa en el constructor. los CityPreference.java La clase debería verse así:

paquete ah.hathi.simpleweather; importar android.app.Activity; importar android.content.SharedPreferences; clase pública CityPreference SharedPreferences prefs; public CityPreference (Activity activity) prefs = activity.getPreferences (Activity.MODE_PRIVATE);  // Si el usuario aún no ha elegido una ciudad, devuelve // ​​Sydney como la ciudad predeterminada Cadena getCity () return prefs.getString ("city", "Sydney, AU");  void setCity (String city) prefs.edit (). putString ("city", city) .commit (); 

11. Crea el Fragmento

Crear una nueva clase de Java y nombrarla WeatherFragment.java. Este fragmento utiliza fragment_weather.xml como su diseño. Declarar los cinco Vista de texto objetos e inicializarlos en el onCreateView método. Declarar un nuevo Tipo de letra objeto llamado climaFont. los TypeFace objeto apuntará a la fuente web que descargó y almacenó en el activos / fuentes carpeta.

Estaremos haciendo uso de un separado Hilo para obtener datos de forma asíncrona de la API de OpenWeatherMap. No podemos actualizar la interfaz de usuario desde tal subproceso en segundo plano. Por lo tanto necesitamos un Entrenador de animales Objeto, que inicializamos en el constructor del Tiempofragmento clase.

la clase pública WeatherFragment extiende Fragment Typeface weatherFont; TextView cityField; TextView updatedField; TextView detailsField; TextView currentTemperatureField; TextView weatherIcon; Manejador de manejador; Public WeatherFragment () handler = new Handler ();  @Override public View onCreateView (inflador de LayoutInflater, ViewGroup, Bundle savedInstanceState) View rootView = inflater.inflate (R.layout.fragment_weather, container, false); cityField = (TextView) rootView.findViewById (R.id.city_field); updatedField = (TextView) rootView.findViewById (R.id.updated_field); detailsField = (TextView) rootView.findViewById (R.id.details_field); currentTemperatureField = (TextView) rootView.findViewById (R.id.current_temperature_field); weatherIcon = (TextView) rootView.findViewById (R.id.weather_icon); weatherIcon.setTypeface (weatherFont); devuelve rootView; 

Inicializar el climaFont objetar llamando crearFromAsset sobre el Tipo de letra clase. También invocamos el updateWeatherData método en onCreate.

@Override public void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); weatherFont = Typeface.createFromAsset (getActivity (). getAssets (), "fonts / weather.ttf"); updateWeatherData (new CityPreference (getActivity ()). getCity ()); 

En updateWeatherData, Empezamos un nuevo hilo y llamamos. getJSON sobre el RemoteFetch clase. Si el valor devuelto por getJSON es nulo, mostramos un mensaje de error al usuario. Si no es así, invocamos el renderWeather método.

Solo el principal Hilo Se le permite actualizar la interfaz de usuario de una aplicación de Android. Vocación tostada o renderWeather directamente desde el subproceso en segundo plano llevaría a un error de tiempo de ejecución. Es por eso que llamamos a estos métodos usando el entrenador de animaleses enviar método.

private void updateWeatherData (final String city) new Thread () public void run () final JSONObject json = RemoteFetch.getJSON (getActivity (), city); if (json == null) handler.post (new Runnable () public void run () Toast.makeText (getActivity (), getActivity (). getString (R.string.place_not_found), Toast.LENGTH_LONG) .show (););  else handler.post (new Runnable () public void run () renderWeather (json););   .comienzo(); 

los renderWeather método utiliza los datos JSON para actualizar el Vista de texto objetos. los clima El nodo de la respuesta JSON es una matriz de datos. En este tutorial, solo usaremos el primer elemento de la matriz de datos meteorológicos.

private void renderWeather (JSONObject json) try cityField.setText (json.getString ("name"). toUpperCase (Locale.US) + "," + json.getJSONObject ("sys"). getString ("country")) ; Detalles de JSONObject = json.getJSONArray ("weather"). GetJSONObject (0); JSONObject main = json.getJSONObject ("main"); detailsField.setText (details.getString ("description"). toUpperCase (Locale.US) + "\ n" + "Humedad:" + main.getString ("temperature") + "%" + "\ n" + "Presión : "+ main.getString (" pressure ") +" hPa "); currentTemperatureField.setText (String.format ("%. 2f", main.getDouble ("temp")) + "℃"); DateFormat df = DateFormat.getDateTimeInstance (); String updatedOn = df.format (new Date (json.getLong ("dt") * 1000)); updatedField.setText ("Última actualización:" + updatedOn); setWeatherIcon (details.getInt ("id"), json.getJSONObject ("sys"). getLong ("sunrise") * 1000, json.getJSONObject ("sys"). getLong ("sunset") * 1000);  catch (Exception e) Log.e ("SimpleWeather", "Uno o más campos que no se encuentran en los datos JSON"); 

Al final de renderWeather método, invocamos setWeatherIcon con el carné de identidad del clima actual, así como las horas de salida y puesta del sol. Configurar el ícono del clima es un poco complicado, porque la API de OpenWeatherMap admite más condiciones meteorológicas de las que podemos admitir con la fuente web que estamos usando. Afortunadamente, las identificaciones climáticas siguen un patrón, sobre el que puede leer más en el sitio web OpenWeatherMap.

Así es como asignamos una identificación del tiempo a un icono:

  • Los códigos meteorológicos en el rango 200 están relacionados con tormentas eléctricas, lo que significa que podemos usar R.string.weather_thunder para éstos
  • Los códigos meteorológicos en el rango de 300 están relacionados con las lloviznas y usamos R.string.weather_drizzle para éstos
  • Los códigos meteorológicos en el rango 500 significan lluvia y usamos R.string.weather_rain para ellos
  • y así…

Usamos las horas de salida y puesta del sol para mostrar el sol o la luna, dependiendo de la hora actual del día y solo si el clima es despejado.

privado void setWeatherIcon (int actualId, long sunrise, long sunset) int id = actualId / 100; Icono de cadena = ""; if (actualId == 800) long currentTime = new Date (). getTime (); if (currentTime> = sunrise && currentTime

Por supuesto, puedes manejar más condiciones climáticas agregando más caso declaraciones a la cambiar declaración de la setWeatherIcon método.

Finalmente, agregue un cambioCiudad Método al fragmento para permitir que el usuario actualice la ciudad actual. los cambioCiudad Método solo será llamado desde el principal Actividad clase.

public void changeCity (String city) updateWeatherData (city); 

12. Edita la actividad

Durante la configuración del proyecto, se completó Eclipse. WeatherActivity.java Con algún código repetitivo. Reemplace la implementación por defecto del onCreate Método con el de abajo en el que usamos el Tiempofragmento. los onCreate El método debería verse así:

@Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_weather); if (savedInstanceState == null) getSupportFragmentManager (). beginTransaction () .add (R.id.container, new WeatherFragment ()) .commit (); 

A continuación, edite el onOptionsItemSelected Método y manejar la única opción de menú que tenemos. Todo lo que tienes que hacer aquí es invocar el showInputDialog método.

En el showInputDialog método, usamos AlertDialog.Builder para crear un Diálogo objeto que solicita al usuario que ingrese el nombre de una ciudad. Esta información se transmite a la cambioCiudad Método, que almacena el nombre de la ciudad utilizando el CityPreference clase y llama al Fragmentoes cambioCiudad método.

@Override public boolean onOptionsItemSelected (elemento MenuItem) if (item.getItemId () == R.id.change_city) showInputDialog ();  falso retorno;  privado void showInputDialog () AlertDialog.Builder builder = new AlertDialog.Builder (esto); builder.setTitle ("Cambiar ciudad"); entrada final de EditText = nuevo EditText (este); input.setInputType (InputType.TYPE_CLASS_TEXT); builder.setView (entrada); builder.setPositiveButton ("Go", nuevo DialogInterface.OnClickListener () @Override public void onClick (diálogo DialogInterface, int which) changeCity (input.getText (). toString ());)); constructor.show ();  public void changeCity (String city) WeatherFragment wf = (WeatherFragment) getSupportFragmentManager () .findFragmentById (R.id.container); wf.changeCity (ciudad); nueva CityPreference (this) .setCity (city); 

Tu aplicación del tiempo ya está lista. Cree el proyecto y despliéguelo en un dispositivo Android para realizar pruebas..

Conclusión

Ahora tienes una aplicación de clima completamente funcional. Siéntase libre de explorar la API de OpenWeatherMap para mejorar aún más su aplicación. También es posible que desee utilizar más iconos del clima, ya que actualmente estamos usando solo un pequeño subconjunto de ellos.