Lag en Været App på Android

Create en Weather App på Android

86
Del
21
Del
Dette Cyber ​​mandag Envato Tuts + Kursene vil bli redusert til bare $ 3. Ikke gå glipp av.
Hva du skal lage

Mange av de populære vær apps på Google Play er enten full av annonser, krever for mange tillatelser, eller inkludere funksjoner som de fleste av oss aldri bruker. Ville det ikke være flott om du kunne bygge din egen vær-app fra bunnen av?

I denne opplæringen, skal jeg vise deg hvordan. Vår app vil ha en enkel og minimalistisk brukergrensesnitt, som viser brukeren nøyaktig hva de trenger å vite om de gjeldende værforhold. La oss komme i gang.

1. Forutsetninger

Før du fortsetter, dobbeltsjekke at du har følgende oppsett:

Eclipse ADT Bundle Bilde: Du kan laste det ned på Android Developer nettstedet .

OpenWeatherMap
API Key Bilde: Dette er ikke nødvendig for å fullføre opplæringen, men det er gratis. Du kan få en ved å registrere deg på OpenWeatherMap nettstedet

Ikoner Bilde:. Jeg anbefaler at du laster ned værikonene font skapt av Erik Flowers. Du må laste ned TTF-filen, fordi vi skal bruke den i en innfødt app. Vi vil bruke skriften til å gjengi ulike ikoner avhengig av værforholdene.

2. Opprett et nytt prosjekt

Jeg kommer til å kalle dette programmet SimpleWeather
, men gjerne gi den et navn du liker. Angi et unikt pakkenavn, satt minstekravet SDK til Android 2.2
, og angi målet SDK til Android 4.4
. Du kan la tema på Holo Mørk
.

Denne applikasjonen vil bare ha én aktivitet, og det vil være basert på Blank aktivitet
malen som vist nedenfor .

navn aktivitets WeatherActivity
. Vi skal bruke en Fragment inne i denne aktiviteten. Oppsettet er knyttet til aktivitet er activity_weather.xml
. Oppsettet forbundet med Fragment er fragment_weather.xml
.

3. Tilsett Custom Font

Kopier weathericons-vanlige-webfont.ttf
til prosjektets eiendeler /fonter katalog og endre navnet til weather.ttf Anmeldelser .

4. Redigere Manifest

Den eneste tillatelse dette programmet trenger er android.permission.INTERNET
< bruker-tillatelse android. Name = "android.permission.INTERNET" />

For å holde denne opplæringen enkel, vi bare kommer til å støtte portrett
modus. Aktiviteten node av manifestet skal se slik ut:
< aktivitet android: name = "ah.hathi.simpleweather.WeatherActivity" android: label = "@ streng /APP_NAME" android: screenOrientation = "portrett" > < intent-filter > < handling android: name = "android.intent.action.MAIN" /> < kategori android: name = "android.intent.category.LAUNCHER" /> < /intent-filter > < /aktivitets >
5. Rediger Aktivitet layout

Det er ikke mye å endre på activity_weather.xml
. Det skal allerede ha en FrameLayout. Legg til en ekstra egenskap til å endre fargen på bakgrunnen til # FF0099CC
< FrameLayout xmlns:. Android = "http://schemas.android.com/apk/res/android" xmlns: verktøy = " http://schemas.android.com/tools "android: id =" + id /container "android: layout_width =" match_parent "Android: layout_height =" match_parent "verktøy: kontekst =" ah.hathi.simpleweather.WeatherActivity " verktøy: ignore = "MergeRootFrame" android: bakgrunn = "# FF0099CC" />
6. Rediger Fragment layout

Rediger fragment_weather.xml
ved å legge fem TextView koder for å vise følgende informasjon:

by og land


gjeldende temperatur

et ikon som viser de gjeldende værforholdene

et tidsstempel som forteller brukeren når været informasjonen ble sist oppdatert

mer detaljert informasjon om gjeldende vær, for eksempel beskrivelse og fuktighet

Bruk en RelativeLayout å arrangere visninger tekst. Du kan justere Tekststørrelse tilpasset forskjellige enheter
< RelativeLayout xmlns:. Android = "http://schemas.android.com/apk/res/android~~number=plural" xmlns: verktøy = "http: //skjemaer .android.com /verktøy "android: layout_width =" match_parent "android: layout_height =" match_parent "android: paddingBottom =" @ dimen /activity_vertical_margin "android: paddingLeft =" @ dimen /activity_horizontal_margin "android: paddingRight =" @ dimen /activity_horizontal_margin "android: paddingTop =" @ dimen /activity_vertical_margin "verktøy: kontekst =" ah.hathi.simpleweather.WeatherActivity $ PlaceholderFragment "> < TextView android:? id = "+ id /city_field" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_alignParentTop = "true" android: layout_centerHorizontal = "true" android: textAppearance = "android: attr /textAppearanceLarge "/> < TextView android: id = "+ id /updated_field" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_below = "+ id /city_field" android: layout_centerHorizontal = "true" android: textAppearance = "? android: attr /textAppearanceMedium" android: Tekststørrelse = "13sp" /> < TextView android:? id = "+ id /weather_icon" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_centerVertical = "true" android: layout_centerHorizontal = "true" android: textAppearance = "android: attr /textAppearanceLarge "android: Tekststørrelse =" 70sp "/> < TextView android:? id = "+ id /current_temperature_field" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_alignParentBottom = "true" android: layout_centerHorizontal = "true" android: textAppearance = "android: attr /textAppearanceLarge "android: Tekststørrelse =" 40sp "/> < TextView android: id = "+ id /details_field" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_below = "+ id /weather_icon" android: layout_centerHorizontal = "true" android: textAppearance = "? android: attr /textAppearanceMedium" /> < /RelativeLayout >
7. Redigere strings.xml

Denne filen inneholder strengene som brukes i vår app samt Unicode tegnkoder som vi vil bruke til å gjengi været ikoner. Søknaden vil kunne vise åtte forskjellige typer værforhold. Hvis du ønsker å håndtere mer, deretter referere til denne jukselapp. Legg til følgende til verdier /strings.xml Bilde:?
≪ xml version = "1.0" encoding = "UTF-8" > < resources > < string name = "APP_NAME" > Simple Weather < /string > < string name = "change_city" > Endre by < /string > <! - Sett din egen APP ID her - > < string name = "open_weather_maps_app_id" > 11111 < /string > < string name = "weather_sunny" > & # xf00d; < /string > < string name = "weather_clear_night" > & # xf02e; < /string > < string name = "weather_foggy" > & # xf014; < /string > < string name = "weather_cloudy" > & # xf013; < /string > < string name = "weather_rainy" > & # xf019; < /string > < string name = "weather_snowy" > & # xf01b; < /string > < string name = "weather_thunder" > & # xf01e; < /string > < string name = "weather_drizzle" > & # xf01c; < /string > < string name = "place_not_found" >. Beklager, ingen værdata funnet < /string > < /ressurser >
8. Legg et menypunkt

Brukeren skal kunne velge den by som har været de ønsker å se. Rediger meny /weather.xml Hotell og legge til et element for dette alternativet
< meny xmlns:. Android = "http://schemas.android.com/apk/res/android~~number=plural" xmlns: app = "http://schemas.android.com/apk/res-auto~~number=plural" xmlns: verktøy = "http://schemas.android.com/tools~~number=plural" verktøy: kontekst = "ah.hathi.simpleweather.WeatherActivity" > < element android: id = "+ id /change_city" android: orderInCategory = "1" android: title = "@ streng /change_city" app: showAsAction = "aldri" /> < /meny >

Nå at alle XML-filer er klare til bruk, la oss gå videre og spørre OpenWeatherMap API for å hente værdata.

9. Hente data fra OpenWeatherMap

Vi kan få gjeldende vær detaljene i enhver by formatert som JSON bruker OpenWeatherMap API. I søkestrengen, vi passerer byens navn, og det metriske systemet resultatene bør være i

For eksempel, for å få aktuell værinformasjon for Canberra, bruker det metriske systemet, sender vi en forespørsel til http.: //api.openweathermap.org/data/2.5/weather?q=Canberra&units=metric

Responsen vi får tilbake fra API ser slik ut: product: {"base": "CMC stasjoner", "clouds": {"alle": 90}, "torske": 200, "coord": {"lat": -35,28, "lon": 149,13}, "dt": 1404390600, "id ": 2172517," main ": {" fuktighet ": 100," press ": 1023," temp ": -1," temp_max ": -1," temp_min ": -1}," name ":" Canberra " , "sys": {"country": "AU", "message": 0,313, "soloppgang": 1404335563, "solnedgang": 1404370965}, "vær": [{"description": "overskyet skyene", "-ikonet ":" 04n "," id ": 804," viktigste ":" Clouds "}]," vinden ": {" deg ": 305,004," speed ": 1.07}}

Opprett en ny Java klasse og navn det RemoteFetch.java
. Denne klassen er ansvarlig for henting av værdata fra OpenWeatherMap API.

Vi bruker HttpURLConnection klassen å gjøre den eksterne forespørsel. Den OpenWeatherMap API forventer at API-nøkkel i en HTTP-header som heter x-api-nøkkel. Dette er spesifisert i vår forespørsel med setRequestProperty metoden.

Vi bruker en BufferedReader å lese API respons til en Stringbuffer. Når vi har fullstendig respons, vi konvertere den til en JSONObject objekt.

Som du kan se i ovennevnte svar, inneholder JSON data et felt som heter torsk. Dens verdi er 200 hvis forespørselen var vellykket. Vi bruker denne verdien for å sjekke om JSON responsen har dagens værinformasjon eller ikke

RemoteFetch.java
klasse skal se slik ut:.
Pakke ah.hathi .simpleweather, import java.io.BufferedReader, import java.io.InputStreamReader, import java.net.HttpURLConnection, import java.net.URL, import org.json.JSONObject, import android.content.Context, importere android.util. Logg; public class RemoteFetch {private static endelige String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; public static JSONObject getJSON (Context kontekst, String by) {try {URL url = new URL (String.format (OPEN_WEATHER_MAP_API, city)); HttpURLConnection tilkobling = (HttpURLConnection) url.openConnection (); connection.addRequestProperty ("x-api-key", context.getString (R.string.open_weather_maps_app_id)); BufferedReader leser = new BufferedReader (ny InputStreamReader (connection.getInputStream ())); Stringbuffer json = new Stringbuffer (1024); String tmp = ""; while ((tmp = reader.readLine ()) = null!) json.append (TMP) .append ("\\ n"); reader.close (); JSONObject data = new JSONObject (json.toString ()); //Denne verdien vil være 404 dersom anmodningen ikke ble //vellykket hvis (data.getInt ("torsk") = 200!) {Return null; } Returnere data; } catch (Exception e) {return null; }}}
10. Oppbevar City som en preferanse

Brukeren skal ikke behøve å oppgi navnet på byen hver gang de ønsker å bruke programmet. Appen skal huske den siste byen brukeren var interessert i. Vi gjør dette ved å gjøre bruk av SharedPreferences. Men i stedet for direkte tilgang til disse innstillingene fra vår aktivitet klassen, er det bedre å lage en egen klasse for dette formålet.

Opprett en ny Java-klassen og gi den navnet CityPreference.java
. Til å lagre og hente navnet på byen, skape to metoder setCity og getCity. Den SharedPreferences Objektet er initialisert i konstruktøren. CityPreference.java
klasse skal se slik ut:
pakken ah.hathi.simpleweather, import android.app.Activity, import android.content.SharedPreferences, offentlige klasse CityPreference {SharedPreferences prefs; offentlig CityPreference (Activity aktivitet) {prefs = activity.getPreferences (Activity.MODE_PRIVATE); } //Hvis brukeren ikke har valgt en by ennå, returnere //Sydney som standard byen String getCity () {return prefs.getString ("by", "Sydney, AU"); } Void setCity (String by) {prefs.edit () putString ("by", by) .commit (.); }}
11. Opprett Fragment

Opprett en ny Java-klassen og den navnet WeatherFragment.java
. Dette fragmentet bruker fragment_weather.xml
som sin layout. Erklærer de fem TextView gjenstander og initial dem i onCreateView metoden. Erklære en ny Face objekt heter weatherFont. Den skriftsnitt objektet vil peke på web skriften du lastet ned og lagret i eiendeler /fonter
mappe.

Vi vil gjøre bruk av en separat melding til asynkront hente data fra OpenWeatherMap API. Vi kan ikke oppdatere brukergrensesnittet fra en slik bakgrunn tråd. Vi trenger derfor en Handler objekt, som vi initial i konstruktøren av WeatherFragment klassen
public class WeatherFragment strekker Fragment {Face weatherFont.; TextView cityField; TextView updatedField; TextView detailsField; TextView currentTemperatureField; TextView weatherIcon; Handler handler; offentlig WeatherFragment () {handler = new Handler (); }Override Offentlig Vis onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {Vis 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); returnere rootView; }}

Initial weatherFont objekt ved å ringe createFromAsset på Skrifttype klasse. Vi påberope også updateWeatherData metoden i onCreate
Overridepublic void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState.); weatherFont = Typeface.createFromAsset (getActivity () getAssets () ", fonter /weather.ttf".); updateWeatherData (. ny CityPreference (getActivity ()) getCity ());}

I updateWeatherData, starter vi en ny tråd og kaller getJSON på RemoteFetch klasse. Hvis verdien returnert av getJSON er null, viser vi en feilmelding til brukeren. Hvis det ikke er det, påberope vi renderWeather metoden.

Bare hoved Tråden er lov til å oppdatere brukergrensesnittet til en Android-app. Ringe Toast eller renderWeather direkte fra bakgrunnen tråden ville føre til en runtime error. Det er derfor vi kaller disse metoder ved hjelp førers innlegget metode.
Private void updateWeatherData (endelig String by) {new Thread () {public void run () {endelige JSONObject json = RemoteFetch.getJSON (getActivity (), city); if (json == null) {handler.post (ny kjørbart () {public void run () {Toast.makeText (getActivity (), getActivity (). getString (R.string.place_not_found), Toast.LENGTH_LONG) .vis ();}}); } Else {handler.post (ny kjørbart () {public void run () {renderWeather (JSON);}}); }}} .start ();}

renderWeather metoden bruker JSON data for å oppdatere TextView stedene. Været node av JSON responsen er en rekke data. I denne opplæringen, vil vi bare være å bruke det første elementet i rekken av værdata.
Private void renderWeather (JSONObject JSON) {try {cityField.setText (json.getString ("navn"). ToUpperCase (Locale.US ) + "," + json.getJSONObject ("sys") getString ("land")).; JSONObject detaljer = json.getJSONArray ("vær") getJSONObject (0).; JSONObject hoved = json.getJSONObject ("main"); . detailsField.setText (details.getString ("description") toUpperCase (Locale.US) + "\\ n" + "Fuktighet:" + main.getString ("fuktighet") + "%" + "\\ n" + "Pressure : "+ 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 ("Siste oppdatering:" + updatedOn); setWeatherIcon (details.getInt ("id"), json.getJSONObject ("sys") getLong ("soloppgang") * 1000, json.getJSONObject ("sys") getLong ("solnedgang") * 1000..); } catch (Exception e) {Log.e ("SimpleWeather", "En eller flere felt som ikke finnes i JSON data"); }}

På slutten av renderWeather metoden, påberope vi setWeatherIcon med id av dagens vær samt tider av soloppgang og solnedgang. Stille vær-ikonet er litt vanskelig, fordi OpenWeatherMap API støtter flere værforhold enn vi kan støtte med web font vi bruker. Heldigvis været IDer følger et mønster, som du kan lese mer om på OpenWeatherMap nettstedet

Dette er hvordan vi kartlegge en vær id til et ikon.

  • været koder i 200-serien er relatert til tordenvær, noe som betyr at vi kan bruke R.string.weather_thunder for disse

    været kodene i 300-området er knyttet til drizzles og vi bruker R.string.weather_drizzle for disse

    været kodene i 500 serien betegne regn og vi bruker R.string.weather_rain for dem

    og så videre ...

    Vi bruker soloppgang og solnedgang for å vise solen eller månen, avhengig av gjeldende tid på dagen og bare hvis været er klart.
    private void setWeatherIcon (int actualId, lang soloppgang, lang solnedgang) {int id = actualId /100; String icon = ""; . if (actualId == 800) {lang currentTime = new Date () getTime (); if (currentTime > = soloppgang & & currentTime < solnedgang) {ikon = getActivity () getString (R.string.weather_sunny.); } Else {ikon = getActivity () getString (R.string.weather_clear_night.); }} Else {switch (id) {case. 2: icon = getActivity () getString (R.string.weather_thunder); gå i stykker; case 3:. icon = getActivity () getString (R.string.weather_drizzle); gå i stykker; case. 7: icon = getActivity () getString (R.string.weather_foggy); gå i stykker; Ved 8:. icon = getActivity () getString (R.string.weather_cloudy); gå i stykker; case 6:. icon = getActivity () getString (R.string.weather_snowy); gå i stykker; case 5:. icon = getActivity () getString (R.string.weather_rainy); gå i stykker; }} WeatherIcon.setText (ikon);.}

    Selvfølgelig, du kan håndtere flere værforhold ved å legge til flere case uttalelser til bryteren uttalelse av setWeatherIcon metoden

    Til slutt legger du en changeCity metode til fragment å la brukeren oppdatere den byen. Den changeCity metoden vil bare kalles fra hoved aktivitet klassen
    public void changeCity (String by) {updateWeatherData (by);}.
    12. Rediger Aktivitet

    I løpet av prosjektoppsett, Eclipse befolket WeatherActivity.java
    med noen standardtekst kode. Erstatte standard gjennomføringen av onCreate metoden med den nedenfor der bruker vi WeatherFragment. Den onCreate metoden skal se slik ut:
    Overrideprotected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_weather); if (savedInstanceState == null) {getSupportFragmentManager () beginTransaction () .Legg (R.id.container, ny WeatherFragment ()) .commit (.); }}

    Neste, redigere onOptionsItemSelected metoden og håndtere den eneste menyvalget vi har. Alt du trenger å gjøre her er påberope showInputDialog metoden.

    I showInputDialog metode, bruker vi AlertDialog.Builder å skape et Dialog objekt som ber brukeren om å skrive inn navnet på en by. Denne informasjonen blir sendt videre til changeCity metoden, som lagrer navnet på byen ved hjelp av CityPreference klassen og kaller Fragment sin changeCity metode.
    Overridepublic Boolsk onOptionsItemSelected (MENUITEM element) {if (item.getItemId () == R .id.change_city) {showInputDialog (); } Return false;} private void showInputDialog () {AlertDialog.Builder byggmester = new AlertDialog.Builder (denne); builder.setTitle ("Change by"); endelig EditText innspill = new EditText (denne); input.setInputType (InputType.TYPE_CLASS_TEXT); builder.setView (input); builder.setPositiveButton ("Go", ny DialogInterface.OnClickListener () {Override public void onClick (DialogInterface dialog, int som) {changeCity (input.getText () toString ());.}}); builder.show ();} public void changeCity (String by) {WeatherFragment wf = (WeatherFragment) getSupportFragmentManager () .findFragmentById (R.id.container); wf.changeCity (by); ny CityPreference (denne) .setCity (by);}

    Din vær app er nå klar. Bygge prosjektet og distribuere den til en Android-enhet for testing.

    Konklusjon

    Du har nå en fullt funksjonell vær søknad. Føl deg fri til å utforske OpenWeatherMap API for å ytterligere forbedre søknaden din. Du kan også være lurt å benytte seg av flere måleikoner, fordi vi bruker for øyeblikket bare en liten del av dem.