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.
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 MarketSau, 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.
Înainte de a continua, verificați din nou că aveți următoarele setări:
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.
Copie weathericons-regulate-webfont.ttf la proiectul tău Active / fonturi director și redenumiți-l la weather.ttf.
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:
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
.
Editați | × fragment_weather.xml prin adăugarea a cinci TextView
pentru a afișa următoarele informații:
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.
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.
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.
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;
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 ();
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ă:
R.string.weather_thunder
pentru acesteaR.string.weather_drizzle
pentru acesteaR.string.weather_rain
pentru eiUtiliză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 && currentTimeDesigur, puteți face mai multe condiții meteorologice adăugând mai mult
caz
declarații cătreintrerupator
declarație asetWeatherIcon
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 folosimWeatherFragment
.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țishowInputDialog
metodă.În
showInputDialog
metoda pe care o folosimAlertDialog.Builder
pentru a crea undialog
obiect care solicită utilizatorului să introducă numele unui oraș. Aceste informații sunt transmise cătrechangeCity
, care stochează numele orașului folosindCityPreference
clasa și solicităFragment
„schangeCity
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.