Crea un'app Meteo su Android

Cosa starai creando

Molte delle app meteo più diffuse su Google Play sono piene di annunci, richiedono troppe autorizzazioni o includono funzionalità che la maggior parte di noi non usa mai. Non sarebbe bello se tu potessi costruire da zero la tua app meteo?

In questo tutorial, ti mostrerò come. La nostra app avrà un'interfaccia utente semplice e minimalista, che mostra all'utente esattamente ciò che è necessario sapere sulle condizioni meteorologiche attuali. Iniziamo.

Alla ricerca di una scorciatoia?

Questo tutorial ti insegnerà a costruire un'app meteo da zero, ma un'alternativa è quella di utilizzare uno dei modelli di app meteo per Android sul mercato Envato.

Ad esempio, Weminder fornisce un'interfaccia utente semplice e pulita e tutte le funzionalità essenziali di un'app meteo, in modo che tu possa personalizzarla per i tuoi scopi.

Modello di app meteo Weminder sul mercato Envato

Oppure, se vuoi qualcosa di unico e costruito su misura, vai su Envato Studio per dare un'occhiata alla selezione di servizi di sviluppo di app per dispositivi mobili offerti qui.

1. Prerequisiti

Prima di continuare, controlla di avere la seguente configurazione:

  • Pacchetto Eclipse ADT: Puoi scaricarlo dal sito web degli sviluppatori Android.
  • OpenWeatherMap Chiave API : Non è necessario per completare il tutorial, ma è gratuito. Puoi ottenerne uno registrandoti sul sito web di OpenWeatherMap.
  • Icone: Ti consiglio di scaricare il font icone meteo creato da Erik Flowers. Devi scaricare il file TTF, perché lo useremo in un'app nativa. Useremo il font per rendere varie icone a seconda delle condizioni meteorologiche.

2. Crea un nuovo progetto

Chiamerò questa app SimpleWeather, ma sentiti libero di dargli un nome che ti piace. Immettere un nome pacchetto univoco, impostare l'SDK minimo richiesto su Android 2.2, e impostare l'SDK di destinazione su Android 4.4. Puoi lasciare il tema a Holo Dark.

Questa app ne avrà solo una Attività e sarà basato sul Attività vuota modello come mostrato di seguito.

Dai il nome a Attività WeatherActivity. Useremo un Frammento dentro questo Attività. Il layout associato al Attività è activity_weather.xml. Il layout associato al Frammento è fragment_weather.xml.

3. Aggiungi il carattere personalizzato

copia weathericons-regular-webfont.ttf al tuo progetto attività / font directory e rinominarlo in weather.ttf.

4. Modifica il manifest

L'unica autorizzazione di cui ha bisogno l'app è android.permission.INTERNET.


Per mantenere questo tutorial semplice, stiamo solo andando a sostenere ritratto modalità. Il attività il nodo del manifest dovrebbe assomigliare a questo:

     

5. Modifica il layout dell'attività

Non c'è molto da cambiare activity_weather.xml. Dovrebbe già avere un FrameLayout. Aggiungi una proprietà extra per cambiare il colore del sfondo a # FF0099CC.

 

6. Modifica il layout del frammento

modificare fragment_weather.xml aggiungendo cinque TextView tag per mostrare le seguenti informazioni:

  • città e nazione
  • temperatura attuale
  • un'icona che mostra le condizioni meteorologiche attuali
  • un timestamp che indica all'utente quando le informazioni meteorologiche sono state aggiornate l'ultima volta
  • informazioni più dettagliate sul tempo attuale, come descrizione e umidità

Usare un RelativeLayout per organizzare le viste del testo. È possibile regolare il dimensione del testo per adattarsi a vari dispositivi.

       

7. Modifica strings.xml

Questo file contiene le stringhe utilizzate nella nostra app e i codici dei caratteri Unicode che useremo per rendere le icone del tempo. L'applicazione sarà in grado di visualizzare otto diversi tipi di condizioni meteorologiche. Se vuoi gestire di più, fai riferimento a questo cheat sheet. Aggiungi il seguente a Valori / strings.xml:

  Meteo semplice Cambia città  11111 & # Xf00d; & # Xf02e; & # Xf014; & # Xf013; & # Xf019; & # Xf01b; & # Xf01e; & # Xf01c; Siamo spiacenti, nessun dato meteo trovato. 

8. Aggiungi una voce di menu

L'utente dovrebbe essere in grado di scegliere la città di cui vogliono vedere il tempo. modificare MENU / weather.xml e aggiungere un elemento per questa opzione.

  

Ora che tutti i file XML sono pronti per l'uso, passiamo e interrogiamo l'API di OpenWeatherMap per recuperare i dati meteo.

9. Recupera i dati da OpenWeatherMap

Possiamo ottenere i dettagli meteo attuali di qualsiasi città formattata come JSON utilizzando l'API OpenWeatherMap. Nella stringa di query, passiamo il nome della città e il sistema di misura in cui devono essere inseriti i risultati.

Ad esempio, per ottenere le informazioni meteo attuali per Canberra, utilizzando il sistema metrico, inviamo una richiesta a http://api.openweathermap.org/data/2.5/weather?q=Canberra&units=metric

La risposta che otteniamo dall'API è la seguente:

"base": "cmc stations", "clouds": "all": 90, "cod": 200, "coord": "lat": -35.28, "lon": 149.13, "dt" : 1404390600, "id": 2172517, "main": "umidità": 100, "pressione": 1023, "temp": -1, "temp_max": -1, "temp_min": -1, "nome ":" Canberra "," sys ": " paese ":" AU "," messaggio ": 0.313," alba ": 1404335563," tramonto ": 1404370965," meteo ": [" descrizione ":" nuvoloso clouds "," icon ":" 04n "," id ": 804," main ":" Clouds "]," wind ": " deg ": 305.004," speed ": 1.07

Crea una nuova classe Java e chiamala RemoteFetch.java. Questa classe è responsabile del recupero dei dati meteorologici dall'API OpenWeatherMap.

Noi usiamo il HttpURLConnection classe per fare la richiesta remota. L'API OpenWeatherMap prevede la chiave API in un'intestazione HTTP denominata x-api-chiave. Questo è specificato nella nostra richiesta utilizzando il setRequestProperty metodo.

Noi usiamo a BufferedReader leggere la risposta dell'API in a StringBuffer. Quando avremo la risposta completa, la convertiamo in a JSONObject oggetto.

Come puoi vedere nella risposta sopra, i dati JSON contengono un campo chiamato merluzzo. Il suo valore è 200 se la richiesta ha avuto successo. Utilizziamo questo valore per verificare se la risposta JSON ha o meno le informazioni meteo correnti.

Il RemoteFetch.java la classe dovrebbe assomigliare a questa:

pacchetto ah.hathi.simpleweather; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONObject; importare android.content.Context; import android.util.Log; public class RemoteFetch Stringa finale statica privata OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; public static JSONObject getJSON (Context context, String city) try URL url = new URL (String.format (OPEN_WEATHER_MAP_API, city)); HttpURLConnection connection = (HttpURLConnection) url.openConnection (); connection.addRequestProperty ("x-api-key", context.getString (R.string.open_weather_maps_app_id)); Lettore BufferedReader = new BufferedReader (new InputStreamReader (connection.getInputStream ())); StringBuffer json = new StringBuffer (1024); Stringa; while ((tmp = reader.readLine ())! = null) json.append (tmp) .append ("\ n"); reader.close (); JSONObject data = new JSONObject (json.toString ()); // Questo valore sarà 404 se la richiesta non è // corretta se (data.getInt ("cod")! = 200) return null;  dati di ritorno;  catch (Exception e) return null; 

10. Conservare la città come preferenza

L'utente non deve specificare il nome della città ogni volta che desidera utilizzare l'app. L'app dovrebbe ricordare l'ultima città a cui l'utente era interessato. Facciamo questo facendo uso di SharedPreferences. Tuttavia, invece di accedere direttamente a queste preferenze dal nostro Attività classe, è meglio creare una classe separata per questo scopo.

Crea una nuova classe Java e chiamala CityPreference.java. Per memorizzare e recuperare il nome della città, creare due metodi setCity e getCity. Il SharedPreferences l'oggetto è inizializzato nel costruttore. Il CityPreference.java la classe dovrebbe assomigliare a questa:

pacchetto ah.hathi.simpleweather; importare android.app.Activity; importare android.content.SharedPreferences; public class CityPreference prefs di SharedPreferences; public CityPreference (Attività dell'attività) prefs = activity.getPreferences (Activity.MODE_PRIVATE);  // Se l'utente non ha ancora scelto una città, restituisce // Sydney come città predefinita String getCity () return prefs.getString ("city", "Sydney, AU");  void setCity (String city) prefs.edit (). putString ("city", city) .commit (); 

11. Crea il frammento

Crea una nuova classe Java e chiamala WeatherFragment.java. Questo frammento utilizza fragment_weather.xml come il suo layout. Dichiara il cinque TextView oggetti e inizializzarli nel onCreateView metodo. Dichiara un nuovo carattere tipografico oggetto chiamato weatherFont. Il TypeFace oggetto punterà al carattere web scaricato e memorizzato nel attività / font cartella.

Faremo uso di un separato Filo per prelevare in modo asincrono i dati dall'API OpenWeatherMap. Non possiamo aggiornare l'interfaccia utente da tale thread in background. Abbiamo quindi bisogno di un handler oggetto, che inizializziamo nel costruttore del WeatherFragment classe.

la classe pubblica WeatherFragment estende Fragment Typeface weatherFont; TextView cityField; TextView updatedField; TextView detailsField; TextView currentTemperatureField; TextView weatherIcon; Gestore dell'handler; public WeatherFragment () handler = new Handler ();  @Override public Visualizza onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) Visualizza 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); return rootView; 

Inizializza il weatherFont oggetto chiamando createFromAsset sul carattere tipografico classe. Invochiamo anche il updateWeatherData metodo in onCreate.

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

Nel updateWeatherData, iniziamo una nuova discussione e chiamiamo getJSON sul RemoteFetch classe. Se il valore restituito da getJSON è nullo, mostriamo un messaggio di errore all'utente. Se non lo è, invochiamo il renderWeather metodo.

Solo il principale Filo è autorizzato ad aggiornare l'interfaccia utente di un'app Android. chiamata Crostini o renderWeather direttamente dal thread in background causerebbe un errore di runtime. Questo è il motivo per cui chiamiamo questi metodi usando il gestore'S inviare metodo.

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

Il renderWeather metodo utilizza i dati JSON per aggiornare il TextView oggetti. Il tempo metereologico il nodo della risposta JSON è una matrice di dati. In questo tutorial, utilizzeremo solo il primo elemento della serie di dati meteo.

private void renderWeather (JSONObject json) try cityField.setText (json.getString ("name"). toUpperCase (Locale.US) + "," + json.getJSONObject ("sys"). getString ("paese")) ; Dettagli JSONObject = json.getJSONArray ("weather"). GetJSONObject (0); JSONObject main = json.getJSONObject ("main"); detailsField.setText (details.getString ("description"). toUpperCase (Locale.US) + "\ n" + "Umidità:" + main.getString ("umidità") + "%" + "\ n" + "Pressione : "+ 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 ("Ultimo aggiornamento:" + 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 più campi non trovati nei dati JSON"); 

Alla fine di renderWeather metodo, invochiamo setWeatherIcon con il id del tempo attuale e delle ore dell'alba e del tramonto. L'impostazione dell'icona del meteo è un po 'complicata, perché l'API di OpenWeatherMap supporta più condizioni meteorologiche di quelle che possiamo supportare con il font web che stiamo usando. Fortunatamente, gli ID del tempo seguono uno schema, che puoi leggere di più sul sito web di OpenWeatherMap.

Questo è il modo in cui mappiamo un ID meteo a un'icona:

  • i codici meteo nella gamma 200 sono legati ai temporali, il che significa che possiamo usare R.string.weather_thunder per questi
  • i codici di tempo nella gamma 300 sono legati a pioviggini e usiamo R.string.weather_drizzle per questi
  • i codici meteo nella gamma 500 indicano la pioggia e usiamo R.string.weather_rain per loro
  • e così via…

Usiamo gli orari di alba e tramonto per visualizzare il sole o la luna, a seconda dell'ora corrente del giorno e solo se il tempo è chiaro.

private void setWeatherIcon (int actualId, long sunrise, long sunset) int id = actualId / 100; String icon = ""; if (actualId == 800) long currentTime = new Date (). getTime (); if (currentTime> = sunrise && currentTime

Certo, puoi gestire più condizioni meteorologiche aggiungendo altro Astuccio dichiarazioni al interruttore dichiarazione del setWeatherIcon metodo.

Infine, aggiungi un changeCity metodo al frammento per consentire all'utente di aggiornare la città corrente. Il changeCity il metodo verrà chiamato solo dal principale Attività classe.

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

12. Modifica l'attività

Durante la configurazione del progetto, Eclipse è popolato WeatherActivity.java con un po 'di codice boilerplate. Sostituire l'implementazione predefinita di onCreate metodo con quello in basso in cui usiamo il WeatherFragment. Il onCreate il metodo dovrebbe assomigliare a questo:

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

Quindi, modifica il onOptionsItemSelected metodo e gestire l'unica opzione di menu che abbiamo. Tutto quello che devi fare qui è invocare il showInputDialog metodo.

Nel showInputDialog metodo, noi usiamo AlertDialog.Builder creare un Dialogo oggetto che richiede all'utente di inserire il nome di una città. Questa informazione è passata al changeCity metodo, che memorizza il nome della città usando il CityPreference classe e chiama il Frammento'S changeCity metodo.

@Override public boolean onOptionsItemSelected (MenuItem item) if (item.getItemId () == R.id.change_city) showInputDialog ();  return false;  private void showInputDialog () AlertDialog.Builder builder = new AlertDialog.Builder (this); builder.setTitle ("Cambia città"); input EditText finale = nuovo EditText (questo); input.setInputType (InputType.TYPE_CLASS_TEXT); builder.setView (ingresso); builder.setPositiveButton ("Go", new DialogInterface.OnClickListener () @Override public void onClick (DialogInterface dialog, int which) changeCity (input.getText (). toString ());); builder.show ();  public void changeCity (String city) WeatherFragment wf = (WeatherFragment) getSupportFragmentManager () .findFragmentById (R.id.container); wf.changeCity (città); nuovo CityPreference (this) .setCity (città); 

La tua app meteo è ora pronta. Costruisci il progetto e distribuiscilo su un dispositivo Android per il test.

Conclusione

Ora hai un'applicazione meteorologica perfettamente funzionante. Sentiti libero di esplorare l'API di OpenWeatherMap per migliorare ulteriormente la tua applicazione. Potresti anche voler utilizzare più icone meteo, perché al momento ne utilizziamo solo un piccolo sottoinsieme.