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.
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 MarketOf, 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.
Controleer voordat u doorgaat of u de volgende instellingen heeft:
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.
Kopiëren weathericons-regular-webfont.ttf naar uw project activa / fonts map en hernoem het naar weather.ttf.
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:
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
.
Bewerk fragment_weather.xml door er vijf toe te voegen Tekstweergave
tags om de volgende informatie te tonen:
Gebruik een Relatieve layout
om de tekstweergaven te regelen. U kunt het aanpassen lettergrootte
geschikt voor verschillende apparaten.
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.
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.
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;
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 ();
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:
R.string.weather_thunder
voor dezeR.string.weather_drizzle
voor dezeR.string.weather_rain
voor henWe 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 && currentTimeNatuurlijk kun je meer weersomstandigheden aan en meer toevoegen
geval
verklaringen voor deschakelaar
verklaring van desetWeatherIcon
methode.Voeg ten slotte een toe
changeCity
methode om het fragment de gebruiker de huidige stad te laten bijwerken. DechangeCity
methode wordt alleen aangeroepen vanuit de mainActiviteit
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 gebruikenWeatherFragment
. DeonCreate
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 hetshowInputDialog
methode.In de
showInputDialog
methode die we gebruikenAlertDialog.Builder
om een te makendialoog
object dat de gebruiker vraagt de naam van een stad in te voeren. Deze informatie wordt doorgegeven aan dechangeCity
methode, die de naam van de stad opslaat met behulp van deCityPreference
klasse en roept deFragment
'schangeCity
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.