Maak een weer-app op Android

Wat je gaat creëren

Veel populaire weer-apps op Google Play zijn vol met advertenties, vereisen te veel rechten of bevatten functies die de meesten van ons nooit gebruiken. Zou het niet geweldig zijn als je vanuit het niets je eigen weer-app kon bouwen?

In deze zelfstudie laat ik je zien hoe. Onze app heeft een eenvoudige en minimalistische gebruikersinterface die de gebruiker precies laat zien wat hij moet weten over de huidige weersomstandigheden. Laten we beginnen.

Op zoek naar een snelkoppeling?

Deze tutorial leert je om een ​​weer-app helemaal zelf te bouwen, maar een alternatief is om een ​​van de Android-weer-app-sjablonen te gebruiken op Envato Market.

Weminder biedt bijvoorbeeld een eenvoudige, overzichtelijke gebruikersinterface en alle essentiële functies van een weer-app, zodat u deze kunt aanpassen voor uw eigen doeleinden.

Weminder-weer-app-sjabloon op Envato Market

Of, als u iets unieks en op maat gemaakt wilt, ga dan naar Envato Studio om de selectie van mobiele en app-ontwikkelingsservices die daar worden aangeboden te bekijken.

1. Aanvangscompetenties

Controleer voordat u doorgaat of u de volgende instellingen heeft:

  • Eclipse ADT-bundel: U kunt het downloaden op de Android Developer-website.
  • OpenWeatherMap API sleutel : Dit is niet vereist om de tutorial te voltooien, maar het is gratis. U kunt er een krijgen door u aan te melden bij de OpenWeatherMap-website.
  • Icons: Ik raad u aan het lettertype voor weerpictogrammen van Erik Flowers te downloaden. U moet het TTF-bestand downloaden, omdat we het in een native app zullen gebruiken. We gebruiken het lettertype om verschillende pictogrammen weer te geven, afhankelijk van de weersomstandigheden.

2. Maak een nieuw project

Ik ga deze app bellen SimpleWeather, maar voel je vrij om het elke naam te geven die je wilt. Voer een unieke pakketnaam in, stel de minimaal vereiste SDK in op Android 2.2, en stel de doel-SDK in op Android 4.4. Je kunt het thema laten staan Holo Dark.

Deze app heeft er maar één Activiteit en het zal gebaseerd zijn op de Lege activiteit sjabloon zoals hieronder getoond.

Noem de Activiteit WeatherActivity. We gebruiken een Fragment hierin Activiteit. De lay-out die is gekoppeld aan de Activiteit is activity_weather.xml. De lay-out die is gekoppeld aan de Fragment is fragment_weather.xml.

3. Voeg het aangepaste lettertype toe

Kopiëren weathericons-regular-webfont.ttf naar uw project activa / fonts map en hernoem het naar weather.ttf.

4. Bewerk het manifest

De enige toestemming die deze app nodig heeft, is android.permission.INTERNET.


Om deze tutorial eenvoudig te houden, ondersteunen we alleen portret modus. De activiteit knoop van het manifest zou er als volgt uit moeten zien:

     

5. Bewerk de lay-out van de activiteit

Er valt niet veel in te veranderen activity_weather.xml. Het zou al een moeten hebben FrameLayout. Voeg een extra eigenschap toe om de kleur van de te wijzigen achtergrond naar # FF0099CC.

 

6. Bewerk de indeling van het fragment

Bewerk fragment_weather.xml door er vijf toe te voegen Tekstweergave tags om de volgende informatie te tonen:

  • stad en land
  • Huidige temperatuur
  • een pictogram dat de huidige weersomstandigheden toont
  • een tijdstempel die de gebruiker vertelt wanneer de weersinformatie voor het laatst is bijgewerkt
  • meer gedetailleerde informatie over het huidige weer, zoals beschrijving en vochtigheid

Gebruik een Relatieve layout om de tekstweergaven te regelen. U kunt het aanpassen lettergrootte geschikt voor verschillende apparaten.

       

7. Bewerk strings.xml

Dit bestand bevat de tekenreeksen die in onze app worden gebruikt, evenals de Unicode-tekencodes die we gebruiken om de weerpictogrammen weer te geven. De applicatie kan acht verschillende soorten weersomstandigheden weergeven. Als u meer wilt afhandelen, raadpleeg dan deze spiekbrief. Voeg het volgende toe aan waarden / strings.xml:

  Eenvoudig weer Wijzig stad  11111 & # Xf00d; & # Xf02e; & # Xf014; & # Xf013; & # Xf019; & # Xf01b; & # Xf01e; & # Xf01c; Sorry, geen weergegevens gevonden. 

8. Voeg een menu-item toe

De gebruiker moet de stad kunnen kiezen wiens weer ze willen zien. Bewerk menu / weather.xml en voeg een item toe voor deze optie.

  

Nu alle XML-bestanden klaar zijn voor gebruik, gaan we verder en vragen we de OpenWeatherMap API om weergegevens op te halen.

9. Gegevens ophalen van OpenWeatherMap

We kunnen de actuele weergegevens van elke stad die is opgemaakt als JSON met behulp van de OpenWeatherMap API. In de queryreeks geven we de naam van de stad en het metrische systeem door waarin de resultaten moeten staan.

Als u bijvoorbeeld de actuele weerinformatie voor Canberra wilt opvragen met behulp van het metrische systeem, sturen we een verzoek naar http://api.openweathermap.org/data/2.5/weather?q=Canberra&units=metric

Het antwoord dat we terug krijgen van de API ziet er als volgt uit:

"base": "cmc stations", "clouds": "alle": 90, "cod": 200, "coord": "lat": -35.28, "lon": 149.13, "dt" : 1404390600, "id": 2172517, "main": "humidity": 100, "pressure": 1023, "temp": -1, "temp_max": -1, "temp_min": -1, "name ":" Canberra "," sys ": " country ":" AU "," message ": 0.313," sunrise ": 1404335563," sunset ": 1404370965," weather ": [" description ":" bewolking " clouds "," icon ":" 04n "," id ": 804," main ":" Clouds "]," wind ": " deg ": 305.004," speed ": 1.07

Maak een nieuwe Java-klasse en geef deze een naam RemoteFetch.java. Deze klasse is verantwoordelijk voor het ophalen van de weergegevens uit de OpenWeatherMap API.

Wij gebruiken de HttpURLConnection klasse om het verzoek op afstand te maken. De OpenWeatherMap API verwacht dat de API-sleutel in een HTTP-header wordt genoemd x-api-key. Dit wordt gespecificeerd in ons verzoek met behulp van de setRequestProperty methode.

We gebruiken een BufferedReader om de reactie van de API in a te lezen StringBuffer. Wanneer we het volledige antwoord hebben, zetten we het om naar een JSONObject voorwerp.

Zoals u in het bovenstaande antwoord kunt zien, bevatten de JSON-gegevens een veld met de naam kabeljauw. Zijn waarde is 200 als het verzoek succesvol was. We gebruiken deze waarde om te controleren of het JSON-antwoord de huidige weersinformatie bevat of niet.

De RemoteFetch.java klasse zou er als volgt uit moeten zien:

pakket ah.hathi.simpleweather; importeer java.io.BufferedReader; importeer java.io.InputStreamReader; importeer java.net.HttpURLConnection; importeer java.net.URL; import org.json.JSONObject; importeer android.content.Context; import android.util.Log; public class RemoteFetch private static final String OPEN_WEATHER_MAP_API = "http://api.openweathermap.org/data/2.5/weather?q=%s&units=metric"; public static JSONObject getJSON (Context-context, String-stad) try url-URL = nieuwe URL (String.format (OPEN_WEATHER_MAP_API, stad)); HttpURLConnection-verbinding = (HttpURLConnection) url.openConnection (); connection.addRequestProperty ("x-api-key", context.getString (R.string.open_weather_maps_app_id)); BufferedReader-lezer = nieuwe BufferedReader (nieuwe InputStreamReader (connection.getInputStream ())); StringBuffer json = nieuwe StringBuffer (1024); Draad; while ((tmp = reader.readLine ())! = null) json.append (tmp) .append ("\ n"); reader.close (); JSONObject data = nieuw JSONObject (json.toString ()); // Deze waarde is 404 als het verzoek niet // successful is als (data.getInt ("cod")! = 200) return null;  retourgegevens;  catch (Uitzondering e) return null; 

10. Sla de stad op als een voorkeur

De gebruiker hoeft niet telkens de naam van de stad op te geven wanneer hij de app wil gebruiken. De app moet de laatste stad onthouden waarin de gebruiker geïnteresseerd was. We doen dit door gebruik te maken van Gedeelde voorkeuren. In plaats van rechtstreeks toegang te hebben tot deze voorkeuren vanuit onze Activiteit klasse, is het beter om hiervoor een aparte klasse te maken.

Maak een nieuwe Java-klasse en geef deze een naam CityPreference.java. Gebruik twee methoden om de naam van de stad op te slaan en op te halen setCity en getCity. De Gedeelde voorkeuren object wordt geïnitialiseerd in de constructor. De CityPreference.java klasse zou er als volgt uit moeten zien:

pakket ah.hathi.simpleweather; import android.app.Activity; importeer android.content.SharedPreferences; public class CityPreference preferences SharedPreferences; public CityPreference (activiteitsactiviteit) prefs = activity.getPreferences (Activity.MODE_PRIVATE);  // Als de gebruiker nog geen stad heeft gekozen, geeft u // Sydney als de standaardstad String getCity () return prefs.getString ("city", "Sydney, AU");  void setCity (String city) prefs.edit (). putString ("city", city) .commit (); 

11. Maak het fragment

Maak een nieuwe Java-klasse en geef deze een naam WeatherFragment.java. Dit fragment gebruikt fragment_weather.xml als de lay-out. Verklaar de vijf Tekstweergave objecten en initialiseer ze in de onCreateView methode. Verklaar een nieuw Typeface object met de naam weatherFont. De Typeface object wijst naar het weblettertype dat u hebt gedownload en opgeslagen in de activa / fonts map.

We zullen gebruik maken van een afzonderlijke Draad asynchroon ophalen van gegevens uit de OpenWeatherMap API. We kunnen de gebruikersinterface niet bijwerken vanaf een dergelijke achtergrondthread. We hebben daarom een handler object, dat we initialiseren in de constructor van de WeatherFragment klasse.

public class WeatherFragment breidt Fragment uit Typeface weatherFont; TextView cityField; TextView updatedField; TextView detailsveld; TextView currentTemperatureField; TextView weatherIcon; Handler-handler; public WeatherFragment () handler = new Handler ();  @Override public Bekijk onCreateView (LayoutInflater inflater, ViewGroup-container, Bundel savedInstanceState) View 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; 

Initialiseer de weatherFont object door te bellen createFromAsset op de Typeface klasse. We roepen ook de updateWeatherData methode in onCreate.

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

In updateWeatherData, we beginnen een nieuwe thread en bellen getJSON op de RemoteFetch klasse. Als de waarde is geretourneerd door getJSON is nul, we geven een foutmelding aan de gebruiker. Als dit niet het geval is, roepen we de renderWeather methode.

Alleen de belangrijkste Draad mag de gebruikersinterface van een Android-app bijwerken. Roeping Geroosterd brood of renderWeather rechtstreeks van de achtergronddraad zou leiden tot een runtime-fout. Daarom noemen we deze methoden met behulp van de handler's post methode.

private void updateWeatherData (laatste String stad) new Thread () public void run () final JSONObject json = RemoteFetch.getJSON (getActivity (), city); if (json == null) handler.post (nieuw Runnable () public void run () Toast.makeText (getActivity (), getActivity (). getString (R.string.place_not_found), Toast.LENGTH_LONG) .show (););  else handler.post (nieuw Runnable () public void run () renderWeather (json););  .start (); 

De renderWeather methode gebruikt de JSON-gegevens om de Tekstweergave voorwerpen. De weer knooppunt van de JSON-respons is een array met gegevens. In deze zelfstudie gebruiken we alleen het eerste element van de reeks weergegevens.

private void renderWeather (JSONObject json) try cityField.setText (json.getString ("name"). toUpperCase (Locale.US) + "," + json.getJSONObject ("sys"). getString ("land")) ; JSONObject details = json.getJSONArray ("weer"). GetJSONObject (0); JSONObject main = json.getJSONObject ("main"); detailsField.setText (details.getString ("description"). toUpperCase (Locale.US) + "\ n" + "Vochtigheid:" + main.getString ("humidity") + "%" + "\ n" + "Druk : "+ main.getString (" pressure ") +" hPa "); currentTemperatureField.setText (String.format ("%. 2f", main.getDouble ("temp")) + "℃"); DateFormat df = DateFormat.getDateTimeInstance (); String updatedOn = df.format (nieuwe datum (json.getLong ("dt") * 1000)); updatedField.setText ("Laatste update:" + updatedOn); setWeatherIcon (details.getInt ("id"), json.getJSONObject ("sys"). getLong ("sunrise") * 1000, json.getJSONObject ("sys"). getLong ("sunset") * 1000);  catch (Uitzondering e) Log.e ("SimpleWeather", "Een of meer velden niet gevonden in de JSON-gegevens"); 

Aan het einde van de renderWeather methode, roepen we aan setWeatherIcon met de ID kaart van het huidige weer en de tijden van zonsopgang en zonsondergang. Het instellen van het weerpictogram is een beetje lastig, omdat de OpenWeatherMap API meer weersomstandigheden ondersteunt dan we kunnen ondersteunen met het weblettertype dat we gebruiken. Gelukkig volgen de weer-ID's een patroon, waarover je meer kunt lezen op de OpenWeatherMap-website.

Dit is hoe we een weer-ID toewijzen aan een pictogram:

  • de weerscodes in het 200-bereik zijn gerelateerd aan onweersbuien, wat betekent dat we kunnen gebruiken R.string.weather_thunder voor deze
  • de weerscodes in het 300-bereik zijn gerelateerd aan motregen en we gebruiken R.string.weather_drizzle voor deze
  • de weerscodes in de 500-reeks duiden op regen en we gebruiken R.string.weather_rain voor hen
  • enzovoorts…

We gebruiken de zonsopgang en zonsondergang tijden om de zon of de maan weer te geven, afhankelijk van de huidige tijd van de dag en alleen als het weer helder is.

private void setWeatherIcon (int actualId, lange zonsopkomst, lange zonsondergang) int id = actualId / 100; Tekenreekspictogram = ""; if (actualId == 800) long currentTime = new Date (). getTime (); if (currentTime> = sunrise && currentTime

Natuurlijk kun je meer weersomstandigheden aan en meer toevoegen geval verklaringen voor de schakelaar verklaring van de setWeatherIcon methode.

Voeg ten slotte een toe changeCity methode om het fragment de gebruiker de huidige stad te laten bijwerken. De changeCity methode wordt alleen aangeroepen vanuit de main Activiteit klasse.

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

12. Bewerk de activiteit

Tijdens de installatie van het project, Eclipse bevolkt WeatherActivity.java met een beetje boilerplate code. Vervang de standaardimplementatie van de onCreate methode met die hieronder waarin we de gebruiken WeatherFragment. De onCreate methode zou er als volgt uit moeten zien:

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

Bewerk vervolgens de onOptionsItemSelected methode en behandel de enige menuoptie die we hebben. Het enige wat je hier hoeft te doen is het showInputDialog methode.

In de showInputDialog methode die we gebruiken AlertDialog.Builder om een ​​te maken dialoog object dat de gebruiker vraagt ​​de naam van een stad in te voeren. Deze informatie wordt doorgegeven aan de changeCity methode, die de naam van de stad opslaat met behulp van de CityPreference klasse en roept de Fragment's changeCity methode.

@Override public boolean onOptionsItemSelected (MenuItem item) if (item.getItemId () == R.id.change_city) showInputDialog ();  return false;  private void showInputDialog () AlertDialog.Builder builder = nieuwe AlertDialog.Builder (this); builder.setTitle ("Wijzig stad"); final EditText input = new EditText (this); input.setInputType (InputType.TYPE_CLASS_TEXT); builder.setView (input); builder.setPositiveButton ("Go", nieuwe 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 (stad); nieuwe CityPreference (this) .setCity (city); 

Je weer-app is nu klaar. Bouw het project en implementeer het voor testen op een Android-apparaat.

Conclusie

U hebt nu een volledig functionele weertoepassing. Voel je vrij om de OpenWeatherMap API te verkennen om je applicatie verder te verbeteren. Misschien wilt u ook meer weerpictogrammen gebruiken, omdat we op dit moment slechts een kleine subset gebruiken.