Lag en vær app på Android

Hva du skal skape

Mange av de populære værappene på Google Play er enten fulle av annonser, krever for mange tillatelser, eller inkluderer funksjoner som de fleste av oss aldri bruker. Ville det ikke vært bra hvis du kunne bygge din egen vær app fra grunnen av?

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

Ser etter en snarvei?

Denne opplæringen vil lære deg å bygge en vær app fra begynnelsen, men ett alternativ er å bruke en av Android Weather App-malene på Envato Market.

For eksempel gir Weminder et enkelt, rent brukergrensesnitt og alle de viktigste funksjonene i et værprogram, slik at du kan tilpasse det til dine egne formål.

Weminder værmeldingsmal på Envato Market

Eller, hvis du vil ha noe unikt og skreddersydd, gå over til Envato Studio for å se utvalget av mobil- og apputviklingstjenester som tilbys der.

1. Forutsetninger

Før du fortsetter, må du kontrollere at du har følgende konfigurasjon:

  • Eclipse ADT Bundle: Du kan laste den ned på Android Developer-nettstedet.
  • OpenWeatherMap API-nøkkel : Dette er ikke nødvendig for å fullføre opplæringen, men det er gratis. Du kan skaffe deg en ved å registrere deg på OpenWeatherMap nettsiden.
  • ikoner: Jeg anbefaler at du laster ned værsikoner fonten skapt av Erik Flowers. Du må laste ned TTF-filen, fordi vi skal bruke den i en innfødt app. Vi bruker skrifttypen til å gjengi forskjellige ikoner avhengig av værforholdene.

2. Lag et nytt prosjekt

Jeg skal ringe denne appen SimpleWeather, men vær så snill å gi det noe navn du liker. Skriv inn et unikt pakke navn, angi minimumskrav til SDK til Android 2.2, og sett mål SDK til Android 4.4. Du kan forlate temaet på Holo Dark.

Denne appen vil bare ha en Aktivitet og det vil være basert på Blank aktivitet mal som vist nedenfor.

Navn på Aktivitet WeatherActivity. Vi bruker en Fragment inne i dette Aktivitet. Oppsettet knyttet til Aktivitet er activity_weather.xml. Oppsettet knyttet til Fragment er fragment_weather.xml.

3. Legg til den egendefinerte skrifttypen

Kopiere weathericons-vanlige-webfont.ttf til prosjektets eiendeler / skrifter katalog og endre navn på det til weather.ttf.

4. Rediger manifestet

Den eneste tillatelsen denne appen trenger er android.permission.INTERNET.


For å holde denne opplæringen enkel, skal vi bare støtte portrett modus. De aktivitet node av manifestet skal se slik ut:

     

5. Rediger aktivitetsoppsettet

Det er ikke mye å forandre seg i activity_weather.xml. Det burde allerede ha a FrameLayout. Legg til en ekstra egenskap for å endre fargen på bakgrunn til # FF0099CC.

 

6. Rediger fragmentets layout

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

  • by og land
  • nåværende temperatur
  • et ikon som viser gjeldende værforhold
  • en tidsstempel som forteller brukeren når værinformasjonen sist ble oppdatert
  • Nærmere informasjon om dagens vær, for eksempel beskrivelse og fuktighet

Bruk en RelativeLayout å ordne tekstvisningen. Du kan justere tekststørrelse for å passe til forskjellige enheter.

       

7. Rediger strings.xml

Denne filen inneholder strenger som brukes i vår app, samt de Unicode-tegnkoder som vi skal bruke til å gjengi værsikoner. Søknaden vil kunne vise åtte forskjellige typer værforhold. Hvis du vil håndtere mer, så referer til dette cheat sheet. Legg til følgende til Verdiene / strings.xml:

  Enkelt vær Bytt by  11111 & # Xf00d; & # Xf02e; & # Xf014; & # Xf013; & # Xf019; & # Xf01b; & # Xf01e; & # Xf01c; Beklager, ingen værdata funnet. 

8. Legg til en menyelement

Brukeren skal kunne velge byen hvis vær de ønsker å se. Redigere meny / weather.xml og legg til et element for dette alternativet.

  

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

9. Hent data fra OpenWeatherMap

Vi kan få dagens værinformasjon om hvilken som helst by som er formatert som JSON ved hjelp av OpenWeatherMap API. I spørrekretsen passerer vi byens navn og det metriske systemet resultatene skal være i.

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

Svaret vi kommer tilbake fra API ser slik ut:

"base": "cmc stasjoner", "clouds": "alle": 90, "torsk": 200, "koord": "lat": -35.28, "lon": 149.13, "dt" : 1404390600, "id": 2172517, "main": "fuktighet": 100, "trykk": 1023, "temp": -1, "temp_max": -1, "temp_min": -1 ":" Canberra "," sys ":" land ":" AU "," melding ": 0.313," soloppgang ": 1404335563," solnedgang ": 1404370965," vær ": [ skyer "," ikon ":" 04n "," id ": 804," main ":" Clouds "]," vind ": " deg ": 305.004," fart ": 1,07

Opprett en ny Java-klasse og gi den navnet RemoteFetch.java. Denne klassen er ansvarlig for å hente værdata fra OpenWeatherMap API.

Vi bruker HttpURLConnection klasse for å gjøre den eksterne forespørselen. OpenWeatherMap API forventer at API-nøkkelen i en HTTP-tittel heter x-api-key. Dette er spesifisert i vår forespørsel ved hjelp av setRequestProperty metode.

Vi bruker en BufferedReader å lese APIs respons i a Stringbuffer. Når vi har det komplette svaret, konverterer vi det til a JSONObject gjenstand.

Som du kan se i svaret ovenfor, inneholder JSON-dataene et navn som heter torsk. Dens verdi er 200 hvis forespørselen var vellykket. Vi bruker denne verdien for å sjekke om JSON-responsen har gjeldende værinformasjon eller ikke.

De RemoteFetch.java klassen skal se slik ut:

pakke ah.hathi.simpleweather; importer java.io.BufferedReader; importer java.io.InputStreamReader; importer java.net.HttpURLConnection; importer java.net.URL; importer org.json.JSONObject; importer android.content.Context; importer android.util.Log; offentlig klasse RemoteFetch privat statisk endelig streng OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; offentlig statisk JSONObject getJSON (Kontekst kontekst, String city) prøv URL url = ny URL (String.format (OPEN_WEATHER_MAP_API, by)); HttpURLConnection forbindelse = (HttpURLConnection) url.openConnection (); connection.addRequestProperty ("x-api-key", context.getString (R.string.open_weather_maps_app_id)); BufferedReader Reader = Ny BufferedReader (Ny InputStreamReader (Connection.getInputStream ())); StringBuffer json = ny StringBuffer (1024); string; mens ((tmp = reader.readLine ())! = null) json.append (tmp) .append ("\ n"); reader.close (); JSONObject data = nytt JSONObject (json.toString ()); // Denne verdien vil være 404 dersom forespørselen ikke var // vellykket hvis (data.getInt ("cod")! = 200) return null;  returnere data;  fangst (unntak e) return null; 

10. Lagre byen som en preferanse

Brukeren må ikke angi navnet på byen hver gang de vil bruke appen. Appen bør huske den siste byen brukeren var interessert i. Vi gjør dette ved å benytte SharedPreferences. Men i stedet for å få direkte tilgang til disse innstillingene fra vår Aktivitet klasse, er det bedre å lage en egen klasse for dette formålet.

Opprett en ny Java-klasse og gi den navnet CityPreference.java. For å lagre og hente navnet på byen, opprett to metoder setCity og getCity. De SharedPreferences objektet initialiseres i konstruktøren. De CityPreference.java klassen skal se slik ut:

pakke ah.hathi.simpleweather; importer android.app.Activity; importer android.content.SharedPreferences; offentlig klasse CityPreference SharedPreferences prefs; offentlig byreferanse (aktivitetsaktivitet) prefs = activity.getPreferences (Activity.MODE_PRIVATE);  // Hvis brukeren ikke har valgt en by ennå, returner // Sydney som standardby String getCity () return prefs.getString ("city", "Sydney, AU");  void setCity (String city) prefs.edit (). putString ("by", by) .commit (); 

11. Opprett fragmentet

Opprett en ny Java-klasse og gi den navnet WeatherFragment.java. Dette fragmentet bruker fragment_weather.xml som sin oppsett. Erklære de fem TextView objekter og initialiser dem i onCreateView metode. Erklære en ny skriftsnitt objekt som heter weatherFont. De skriftsnitt objektet vil peke på webfonten du lastet ned og lagret i eiendeler / skrifter mappe.

Vi vil benytte seg av en egen Tråd å asynkront hente data fra OpenWeatherMap API. Vi kan ikke oppdatere brukergrensesnittet fra en slik bakgrunnstråd. Vi trenger derfor en handler objekt, som vi initialiserer i konstruktøren til WeatherFragment klasse.

offentlig klasse WeatherFragment utvider fragment Typeface weatherFont; TextView cityField; TextView updatedField; TextView detailsField; TextView currentTemperatureField; TextView weatherIcon; Handler handler; offentlig WeatherFragment () handler = new Handler ();  @ Overstyr offentlig visning onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) Se 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; 

Initialiser weatherFont objekt ved å ringe createFromAsset på skriftsnitt klasse. Vi påberoper også updateWeatherData metode i onCreate.

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

I updateWeatherData, Vi starter en ny tråd og ringer getJSON på RemoteFetch klasse. Hvis verdien returneres av getJSON er null, Vi viser en feilmelding til brukeren. Hvis det ikke er det, anvender vi renderWeather metode.

Bare de viktigste Tråd har lov til å oppdatere brukergrensesnittet til en Android-app. ringe Skål eller renderWeather direkte fra bakgrunnen tråden ville føre til en runtime feil. Det er derfor vi kaller disse metodene ved hjelp av behandleren's post metode.

privat ugyldig oppdateringWeatherData (siste trådby) ny tråd () offentlig tomgangsløp () endelig JSONObject json = RemoteFetch.getJSON (getActivity (), by); hvis (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););   .start(); 

De renderWeather Metoden bruker JSON-dataene til å oppdatere TextView objekter. De vær noden til JSON-responsen er en rekke data. I denne opplæringen bruker vi bare det første elementet i utvalg av værdata.

private void renderWeather (JSONObject json) prøv cityField.setText (json.getString ("navn"). toUpperCase (Locale.US) + "," + json.getJSONObject ("sys"). ; JSONObject detaljer = json.getJSONArray ("vær"). GetJSONObject (0); JSONObject main = json.getJSONObject ("main"); detailsFile.setText (detaljer.getString ("beskrivelse"). toUpperCase (Locale.US) + "\ n" + "Fuktighet:" + main.getString ("fuktighet") + "%" + "\ n" + "Trykk : "+ main.getString (" pressure ") +" hPa "); currentTemperatureField.setText (String.format ("%. 2f", main.getDouble ("temp")) + "℃"); DateFormat df = DateFormat.getDateTimeInstance (); String updatedOn = df.format (nytt dato (json.getLong ("dt") * 1000)); updatedField.setText ("Sist oppdatert:" + oppdatertOn); setWeatherIcon (detaljer.getInt ("id"), json.getJSONObject ("sys"). getLong ("soloppgang") * 1000, json.getJSONObject ("sys"). getLong ("solnedgang") * 1000);  fangst (Unntak e) Log.e ("SimpleWeather", "Ett eller flere felt ikke funnet i JSON-dataene"); 

På slutten av renderWeather metode, påberoper vi oss setWeatherIcon med id av det nåværende været samt tidene med soloppgang og solnedgang. Angi værikonet er litt vanskelig, fordi OpenWeatherMap API støtter flere værforhold enn vi kan støtte med nettfonten vi bruker. Heldigvis følger værmeldingene et mønster, som du kan lese mer om på OpenWeatherMap-nettsiden.

Slik kartlegger du et vær-id til et ikon:

  • Værkodene i 200-serien er relatert til tordenvær, noe som betyr at vi kan bruke R.string.weather_thunder for disse
  • Værkodene i 300-serien er relatert til drizzles og vi bruker R.string.weather_drizzle for disse
  • Værkodene i 500-serien betyr regn og vi bruker R.string.weather_rain for dem
  • og så videre…

Vi bruker soloppgang og solnedgangstider for å vise sol eller månen, avhengig av dagens tid og bare hvis været er klart.

privat tomt settWeatherIcon (int actualId, lang soloppgang, lang solnedgang) int id = actualId / 100; Stringikon = ""; hvis (actualId == 800) long currentTime = ny dato (). getTime (); hvis (currentTime> = soloppgang && currentTime

Selvfølgelig kan du takle flere værforhold ved å legge til flere sak uttalelser til bytte om uttalelse av setWeatherIcon metode.

Til slutt legg til en changeCity metode til fragmentet for å la brukeren oppdatere den nåværende byen. De changeCity Metoden vil bare bli hentet fra hovedmenyen Aktivitet klasse.

offentlig ugyldig forandring (String city) updateWeatherData (by); 

12. Rediger aktiviteten

Under prosjektets oppsett befolket Eclipse WeatherActivity.java med litt boilerplate kode. Erstatt standard implementering av onCreate metode med den nedenfor som vi bruker WeatherFragment. De onCreate metoden skal se slik ut:

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

Deretter redigerer du onOptionsItemSelected metode og håndtere det eneste menyalternativet vi har. Alt du trenger å gjøre her er å påkalle showInputDialog metode.

showInputDialog metode, bruker vi AlertDialog.Builder å lage en Dialog objekt som ber brukeren om å skrive inn navnet på en by. Denne informasjonen sendes videre til changeCity metode, som lagrer navnet på byen ved hjelp av CityPreference klasse og kaller Fragment's changeCity metode.

@Override public boolean onOptionsItemSelected (MenuItem item) if (item.getItemId () == R.id.change_city) showInputDialog ();  returner falsk;  private void showInputDialog () AlertDialog.Builder builder = ny AlertDialog.Builder (dette); builder.setTitle ("Bytt by"); Endelig EditText input = Ny EditText (dette); 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 ();  offentlig ugyldig forandringCity (String city) WeatherFragment wf = (WeatherFragment) getSupportFragmentManager () .findFragmentById (R.id.container); wf.changeCity (by); Ny CityPreference (dette) .set City (by); 

Værmeldingen din er nå klar. Bygg prosjektet og distribuere det til en Android-enhet for testing.

Konklusjon

Du har nå et fullt funksjonelt værprogram. Du er velkommen til å utforske OpenWeatherMap API for å forbedre søknaden ytterligere. Du vil kanskje også bruke flere værsikoner, fordi vi for øyeblikket bare bruker en liten delmengde av dem.