Creați o aplicație meteo pe Android

Ce veți crea

Multe aplicații meteorologice populare din Google Play sunt pline de anunțuri, necesită prea multe permisiuni sau includ funcții pe care majoritatea dintre noi nu le folosim niciodată. Nu ar fi minunat dacă ai putea să-ți construiești propria aplicație meteo de la zero?

În acest tutorial, vă voi arăta cum. Aplicația noastră va avea o interfață de utilizator simplă și minimalistă, indicând utilizatorului exact ce trebuie să știe despre condițiile meteorologice curente. Să începem.

Căutați o comandă rapidă?

Acest tutorial vă va învăța să construiți o aplicație meteorologică de la zero, dar o alternativă este să utilizați una dintre șabloanele de aplicații meteo Android pe Envato Market.

De exemplu, Weminder oferă o interfață de utilizator simplă, curată și toate caracteristicile esențiale ale unei aplicații meteo, astfel încât să o puteți personaliza în scopuri proprii.

Weminder temp temp app pe Envato Market

Sau, dacă vreți ceva unic și personalizat, mergeți la Envato Studio pentru a verifica selecția serviciilor mobile și a serviciilor de dezvoltare oferite acolo.

1. Cerințe preliminare

Înainte de a continua, verificați din nou că aveți următoarele setări:

  • Eclipse ADT Bundle: Puteți să o descărcați de pe site-ul Android Developer.
  • OpenWeatherMap Cheia API : Nu este necesară completarea tutorialului, dar este gratuit. Puteți obține unul prin înscrierea la site-ul OpenWeatherMap.
  • icoane: Vă recomandăm să descărcați fontul pentru icoane meteo creat de Erik Flowers. Trebuie să descărcați fișierul TTF, deoarece îl vom folosi într-o aplicație nativă. Vom folosi fontul pentru a afișa diferite pictograme în funcție de condițiile meteorologice.

2. Creați un nou proiect

Voi numi această aplicație SimpleWeather, dar simțiți-vă liber să îi dați orice nume doriți. Introduceți un nume de pachet unic, setați SDK-ul minim necesar Android 2.2, și setați SDK-ul țintă Android 4.4. Puteți lăsa tema la Holo Întuneric.

Această aplicație va avea doar una Activitate și se va baza pe Activitate clară șablon după cum se arată mai jos.

Denumiți Activitate WeatherActivity. Vom folosi o Fragment înăuntru Activitate. Aspectul asociat cu Activitate este activity_weather.xml. Aspectul asociat cu Fragment este fragment_weather.xml.

3. Adăugați Font Custom

Copie weathericons-regulate-webfont.ttf la proiectul tău Active / fonturi director și redenumiți-l la weather.ttf.

4. Editați Manifestul

Singura permisiune pe care o are această aplicație este android.permission.INTERNET.


Pentru a păstra acest tutorial simplu, vom susține doar portret Mod. activitate nodul manifestului ar trebui să arate astfel:

     

5. Modificați aspectul activității

Nu trebuie să schimbăm nimic activity_weather.xml. Ar trebui să aibă deja a FrameLayout. Adăugați o proprietate suplimentară pentru a schimba culoarea fundal la # FF0099CC.

 

6. Editați aspectul fragmentelor

Editați | × fragment_weather.xml prin adăugarea a cinci TextView pentru a afișa următoarele informații:

  • oras si tara
  • temperatura actuală
  • o pictogramă care arată condițiile meteorologice curente
  • un marcaj de timp care spune utilizatorului când informația despre vreme a fost actualizată ultima dată
  • informații mai detaliate despre vremea curentă, cum ar fi descrierea și umiditatea

Folosește o RelativeLayout pentru a aranja vizualizările de text. Aveți posibilitatea să reglați Mărimea textului pentru a se potrivi diferitelor dispozitive.

       

7. Editați strings.xml

Acest fișier conține corzile folosite în aplicația noastră, precum și codurile de caractere Unicode pe care le vom folosi pentru a face pictogramele pentru vreme. Aplicația va putea afișa opt tipuri diferite de condiții meteorologice. Dacă doriți să vă ocupați mai mult, faceți referire la această foaie de înșelătorie. Adăugați următoarele la Valorile / strings.xml:

  Vremea simplă Schimbați orașul  11111 & # Xf00d; & # Xf02e; & # Xf014; & # Xf013; & # Xf019; & # Xf01b; & # Xf01e; & # Xf01c; Ne pare rău, nu s-au găsit date meteorologice. 

8. Adăugați un element de meniu

Utilizatorul ar trebui să poată alege orașul a cărui vreme vrea să vadă. Editați | × meniu / weather.xml și adăugați un element pentru această opțiune.

  

Acum că toate fișierele XML sunt gata de utilizare, hai să mergem mai departe și să interogăm API-ul OpenWeatherMap pentru a prelua date despre vreme.

9. Obțineți date din OpenWeatherMap

Putem obține detaliile meteorologice curente ale oricărui oraș formatat ca JSON utilizând API-ul OpenWeatherMap. În șirul de interogări, trecem numele orașului și sistemul metric în care se găsesc rezultatele.

De exemplu, pentru a obține informațiile meteo curente pentru Canberra, folosind sistemul metric, trimitem o solicitare la http://api.openweathermap.org/data/2.5/weather?q=Canberra&units=metric

Răspunsul pe care îl primim din API arată astfel:

"bază": "stații cmc", "nori": "toate": 90, "cod": 200, "coord" : 1404390600, id id: 2172517, "principal": "umiditate": 100, "presiune": 1023, "temp": -1, "temp_max" ":" Canberra "," sys ": " țară ":" AU "," mesaj ": 0.313," sunrise ": 1404335563," sunset ": 1404370965 nori "," icon ":" 04n "," id ": 804," principal ":" nori "]," vânt ": " deg ": 305,004," viteză ": 1,07

Creați o nouă clasă Java și denumiți-o RemoteFetch.java. Această clasă este responsabilă pentru preluarea datelor meteorologice din API-ul OpenWeatherMap.

Noi folosim HttpURLConnection pentru a face cererea la distanță. API-ul OpenWeatherMap așteaptă cheia API într-un antet HTTP numit x-api-cheie. Acesta este specificat în cererea noastră folosind setRequestProperty metodă.

Noi folosim a BufferedReader pentru a citi răspunsul API în a StringBuffer. Când avem răspunsul complet, îl convertim în a obiect JSON obiect.

După cum puteți vedea în răspunsul de mai sus, datele JSON conțin un câmp numit cod. Valoarea lui este 200 dacă cererea a avut succes. Utilizăm această valoare pentru a verifica dacă răspunsul JSON are sau nu informații meteorologice actuale.

RemoteFetch.java clasa ar trebui să arate astfel:

pachet ah.hathi.simpleweather; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONObject; importați android.content.Context; import șiroid.util.Log; class public RemoteFetch string privat static final OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; staticul public JSONObject getJSON (Contextul contextului, orașul String) try URL url = nou URL (String.format (OPEN_WEATHER_MAP_API, oraș)); Conexiunea HttpURLConnection = (HttpURLConnection) url.openConnection (); connection.addRequestProperty ("x-api-key", context.getString (R.string.open_weather_maps_app_id)); BufferedReader reader = nou BufferedReader (noul InputStreamReader (connection.getInputStream ())); StringBuffer json = nou StringBuffer (1024); Şir; în timp ce ((tmp = reader.readLine ())! = null) json.append (tmp) .append ("\ n"); reader.close (); JSONObject data = nou JSONObject (json.toString ()); // Această valoare va fi 404 dacă cererea nu a fost // reușită dacă (data.getInt ("cod")! = 200) return null;  returnați datele;  captură (excepție e) return null; 

10. Depozitați orașul ca preferință

Utilizatorul nu trebuie să specifice numele orașului de fiecare dată când dorește să utilizeze aplicația. Aplicația ar trebui să-și amintească ultimul oraș în care a fost interesat utilizatorul. Facem acest lucru folosind SharedPreferences. Cu toate acestea, în loc să accesăm direct aceste preferințe din partea noastră Activitate clasa, este mai bine să creați o clasă separată în acest scop.

Creați o nouă clasă Java și denumiți-o CityPreference.java. Pentru a stoca și pentru a prelua numele orașului, creați două metode setCity și getCity. SharedPreferences obiect este inițializat în constructor. CityPreference.java clasa ar trebui să arate astfel:

pachet ah.hathi.simpleweather; importă android.app.Activity; import android.content.SharedPreferences; clasa publica CityPreference SharedPreferences prefs; publicPreference public (Activitate de activitate) prefs = activity.getPreferences (Activity.MODE_PRIVATE);  // Dacă utilizatorul nu a ales încă un oraș, returnează // Sydney ca oraș implicit String getCity () return prefs.getString ("oraș", "Sydney, AU");  void setCity (orașul cu șir) prefs.edit (). putString ("oraș", oraș) .commit (); 

11. Creați fragmentul

Creați o nouă clasă Java și denumiți-o WeatherFragment.java. Acest fragment utilizează fragment_weather.xml ca aspectul său. Declarați cele cinci TextView obiecte și să le inițializeze în onCreateView metodă. Declarați un nou Fontul obiect numit weatherFont. cursive obiect va indica fontul pe care l-ați descărcat și stocat în Active / fonturi pliant.

Vom folosi o soluție separată Fir pentru preluarea asincronă a datelor din API-ul OpenWeatherMap. Nu putem actualiza interfața de utilizator dintr-un astfel de fir de fundal. Prin urmare, avem nevoie de a manipulant obiect, pe care îl inițializăm în constructorul WeatherFragment clasă.

clasa publica WeatherFragment extinde fragmentul Typeface weatherFont; TextView cityField; TextView updatedField; TextView detailsField; TextView currentTemperatureField; TextView weatherIcon; Handler handler; publice WeatherFragment () handler = Handler nou ();  @Overide public View onCreateView (LayoutInflater inflater, Container ViewGroup, Bundle savedInstanceState) View rootView = inflater.inflate (R.layout.fragment_weather, container, false); cityField = (TextView) rădăcinăView.findViewById (R.id.city_field); actualizatField = (TextView) rootView.findViewById (R.id.updated_field); detaliiField = (TextView) rootView.findViewById (R.id.details_field); actualTemperatureField = (TextView) rootView.findViewById (R.id.current_temperature_field); weatherIcon = (TextView) rootView.findViewById (R.id.weather_icon); weatherIcon.setTypeface (weatherFont); returnează rootView; 

Inițializați weatherFont obiect prin apel createFromAsset pe Fontul clasă. De asemenea, invocăm updateWeatherData metoda în onCreate.

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

În updateWeatherData, începem un fir nou și sunăm getJSON pe RemoteFetch clasă. Dacă valoarea returnată de getJSON este nul, afișăm un mesaj de eroare utilizatorului. Dacă nu este, invocăm renderWeather metodă.

Numai principalul Fir este permis să actualizeze interfața de utilizator a unei aplicații Android. apel Paine prajita sau renderWeather direct de la firul de fundal ar duce la o eroare de execuție. De aceea numim aceste metode folosind manipulant„s post metodă.

private void updateWeatherData (orașul final al șirului) new Thread () public void run () final JSONObject json = RemoteFetch.getJSON (getActivity (), oraș); dacă (json == null) handler.post (new Runnable () public void run () Toast.makeText (getActivity (), getActivity (). getString (R.string.place_not_found), Toast.LENGTH_LONG). (););  altceva handler.post (nou Runnable () public void run () renderWeather (json););   .start(); 

renderWeather metoda utilizează datele JSON pentru a actualiza TextView obiecte. vreme nodul răspunsului JSON este o serie de date. În acest tutorial, vom folosi doar primul element al matricei de date meteorologice.

privat void renderWeather (JSONObject json) încercați cityField.setText (json.getString ("name")) toUpperCase (Locale.US) + "," + json.getJSONObject ("sys" ; Detalii JSONObject = json.getJSONArray ("vreme") getJSONObject (0); JSONObject principal = json.getJSONObject ("principal"); detaliiField.setText (details.getString ("descriere") toUpperCase (Locale.US) + "\ n" + "Umiditate:" + main.getString ("umiditate") + : "+ main.getString (" presiune ") +" hPa "); curentTemperatureField.setText (String.format ("%. 2f", main.getDouble ("temp")) + "℃"); DatăFormat df = DateFormat.getDateTimeInstance (); String updatedOn = df.format (noua dată (json.getLong ("dt") * 1000)); updatedField.setText ("Ultima actualizare:" + updatedOn); setWeatherIcon (detalii.getInt ("id"), json.getJSONObject ("sys") getLong ("răsărit") * 1000, json.getJSONObject ("sys").  captură (Excepție e) Log.e ("SimpleWeather", "Unul sau mai multe câmpuri care nu se găsesc în datele JSON"); 

La sfârșitul renderWeather metoda, ne invocăm setWeatherIcon cu id a vremii curente, precum și a perioadelor de răsărit și apus de soare. Setarea pictogramei meteo este un pic dificilă, deoarece API-ul OpenWeatherMap suportă mai multe condiții meteorologice decât cele pe care le putem utiliza cu fontul pe care îl folosim. Din fericire, ID-urile meteorologice urmează un model, despre care puteți citi mai multe despre site-ul OpenWeatherMap.

Acesta este modul în care am maparea unui id de vreme la o pictogramă:

  • codurile meteo din gama 200 sunt legate de furtuni, ceea ce înseamnă că putem folosi R.string.weather_thunder pentru acestea
  • codurile meteo din gama 300 sunt legate de drizzles și le folosim R.string.weather_drizzle pentru acestea
  • codurile meteo din gama 500 înseamnă ploaie și noi folosim R.string.weather_rain pentru ei
  • si asa mai departe…

Utilizăm răsăritul și apusul soarelui pentru a afișa soarele sau luna, în funcție de ora curentă a zilei și numai dacă vremea este clară.

private void setWeatherIcon (int actualId, răsărit de soare lung, apus lung) int id = actualId / 100; Șir de pictograme = ""; dacă (actualId == 800) long currentTime = data nouă (). getTime (); dacă (currentTime> = sunrise && currentTime

Desigur, puteți face mai multe condiții meteorologice adăugând mai mult caz declarații către intrerupator declarație a setWeatherIcon metodă.

În cele din urmă, adăugați a changeCity pentru a permite utilizatorului să actualizeze orașul curent. changeCity metoda se va apela numai din partea principală Activitate clasă.

public void changeCity (orașul cu șir) updateWeatherData (oraș); 

12. Editați Activitatea

În timpul instalării proiectului, Eclipse a fost populată WeatherActivity.java cu un cod de boilerplate. Înlocuiți implementarea implicită a onCreate cu cea de mai jos în care folosim WeatherFragment.  onCreate metoda ar trebui să arate astfel:

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

Apoi, editați onOptionsItemSelected și să gestionăm singura opțiune de meniu pe care o avem. Tot ce trebuie să faceți aici este să invocați showInputDialog metodă.

În showInputDialog metoda pe care o folosim AlertDialog.Builder pentru a crea un dialog obiect care solicită utilizatorului să introducă numele unui oraș. Aceste informații sunt transmise către changeCity , care stochează numele orașului folosind CityPreference clasa și solicită Fragment„s changeCity metodă.

@Override public boolean onOptionsItemSelected (elementul MenuItem) if (item.getItemId () == R.id.change_city) showInputDialog ();  return false;  void privat showInputDialog () AlertDialog.Builder builder = nou AlertDialog.Builder (aceasta); builder.setTitle ("Schimbați orașul"); intrarea finală a textului EditText = noul text EditText (acesta); input.setInputType (InputType.TYPE_CLASS_TEXT); builder.setView (intrare); builder.setPositiveButton ("Go", noul DialogInterface.OnClickListener () @Override public void onClick (dialogul DialogInterface, int care) changeCity (input.getText (). toString ());); builder.show ();  public void changeCity (orașul cu șir) WeatherFragment wf = (WeatherFragment) getSupportFragmentManager () .findFragmentById (R.id.container); wf.changeCity (oraș); new CityPreference (acest) .setCity (oraș); 

Aplicația dvs. pentru vreme este acum pregătită. Construiți proiectul și implementați-l pe un dispozitiv Android pentru testare.

Concluzie

Acum aveți o aplicație meteo pe deplin funcțională. Simțiți-vă liber să explorați API-ul OpenWeatherMap pentru a vă îmbunătăți în continuare aplicația. Poate doriți să utilizați și mai multe pictograme pentru vreme, deoarece în prezent folosim doar un mic subset.

Cod