In deze zelfstudie laat ik je een mogelijke gebruikscasus zien van wat we hebben geleerd in het vorige artikel over Volley. We zullen een weerapplicatie maken voor Mars, met behulp van de informatie verzameld door de Curiosity rover, die door de NASA beschikbaar wordt gemaakt voor iedereen via de MAAS API.
Eerst zullen we het project in Android Studio opzetten en de gebruikersinterface ontwerpen. We zullen dan de kern van de applicatie structureren met behulp van Volley. Omdat elke mooie applicatie een aantal afbeeldingen bevat, zal ik je laten zien hoe je een willekeurige applicatie kunt ophalen met de API van Flickr. We zullen de foto downloaden met Volley, vooral vanwege het geweldige caching-systeem. Ten slotte voegen we enkele mooie details toe om de applicatie een prachtige look en feel te geven.
Maak eerst een nieuw project in Android Studio. Omdat Volley achterwaarts compatibel is, kun je kiezen welk API-niveau je voorkeur heeft. Ik heb gekozen voor API 21, maar het komt wel goed zolang het API-niveau 8 (Froyo) of hoger is.
Onze applicatie heeft een enkele, eenvoudige activiteit. Je kunt het noemen MainActivity.java, zoals gesuggereerd door Android Studio. Open de layout-editor en dubbelklik erop activity_main.xml.
Aangezien we ongeveer 70% van het scherm voor de afbeelding willen hebben en de rest voor de weersinformatie, moeten we het XML-kenmerk gebruiken layout_weight
. Natuurlijk kunnen we ook absolute waarden gebruiken, maar het zou niet hetzelfde zijn. Helaas heeft de Android-wereld schermen die allesbehalve homogeen zijn, en het opgeven van een absolute waarde voor de hoogte van de afbeelding zou kunnen resulteren in een 90-10-verhouding op zeer kleine apparaten en een 70-30 of zelfs een 60-40 relatie, op grotere apparaten. De layout_weight
kenmerk is wat u nodig hebt om dit probleem op te lossen.
Voeg in het eerste kind de Figuurweergave
:
In de seconde Relatieve layout
, we voegen een lijst toe van Tekstweergave
items. Twee ervan zijn weergaven waarin de gemiddelde temperatuur en de ondoorzichtigheid van de atmosfeer worden weergegeven. De derde is een foutlabel.
De lay-out moet nu compleet zijn. U kunt desgewenst meer details toevoegen, maar een complexe en gedetailleerde gebruikersinterface valt niet binnen het bereik van deze zelfstudie.
Er zijn nog twee dingen die we moeten regelen voordat we ons gaan verdiepen in de kern van de applicatie. Wijzig het overgeërfde thema van de toepassing in android: Theme.Material.Light.NoActionBar
. Dit betekent dat we de actiebalk tijdens runtime niet hoeven te verbergen.
Voeg ten slotte de internettoestemming toe aan het manifest van het project.
Zoals we in het vorige artikel hebben besproken, is de eenvoudigste en meest betrouwbare manier om Volley te gebruiken, door de bibliotheek als een nieuwe module te importeren. Download de broncode van de bibliotheek, importeer hem via het dossier > nieuwe > module, en vertel de compiler in het project build.gradle bestand om het in het project op te nemen.
compileer project (": volley")
Zoals ik al in het vorige artikel heb aangegeven, is het beter om een gedeelde verzoekwachtrij te gebruiken als u meerdere verzoeken moet indienen. U moet voorkomen dat u een verzoekwachtrij creëert telkens wanneer u een aanvraag plant door deze aan te roepen Volley.newRequestQueue
, omdat je niet wilt eindigen met geheugenlekken en andere ongewenste problemen.
Om dat te doen, moet je eerst een klasse maken met behulp van het singleton-patroon. Naar de klasse wordt verwezen met behulp van een statische, globaal zichtbare variabele, die het object vervolgens behandelt RequestQueue
. Op deze manier krijg je een single RequestQueue
voor de toepassing. Vervolgens breidt het Toepassing
klasse, moet u het besturingssysteem vertellen om dit object te genereren bij het opstarten van het programma, zelfs voordat de eerste activiteit is gemaakt.
Omdat we in de Android-omgeving werken, passen we de algemene singleton-structuur enigszins aan. De klasse moet een nieuw exemplaar van zichzelf maken in de Application.onCreate
methode - niet in een generiek getInstance
methode wanneer het is nul
.
Om dit te bereiken, maakt u een nieuwe klasse en geeft u deze een naam MarsWeather.java. Breid vervolgens de Android uit Toepassing
klasse, negeer de onCreate
methode, en initialiseer de RequestQueue
object van de statische instantie.
In de singleton-klasse construeren we het object van de klas met een openbaar
en gesynchroniseerd
functie getInstance
. Binnen deze methode geven we de mInstance
variabel. De onCreate
methode wordt aangeroepen wanneer de toepassing wordt gestart, dus de mInstance
variabele zal al de eerste keer dat de getInstance
methode wordt aangeroepen.
openbare klasse MarsWeather breidt Toepassing uit private RequestQueue mRequestQueue; privé statische MarsWeather mInstance; @Override public void onCreate () super.onCreate (); mInstance = dit; mRequestQueue = Volley.newRequestQueue (getApplicationContext ()); openbare statische gesynchroniseerde MarsWeather getInstance () return mInstance;
Vertel het vervolgens in de AndroidManifest.xml bestand dat u wilt MarsWeather
worden geladen bij het opstarten van de toepassing. In de
tag, voeg het attribuut toe naam
als volgt:
android: name = "MarsWeather"
Dat is het. Een exemplaar van de Toepassing
klasse is gemaakt, nog eerder Hoofdactiviteit
is gecreëerd. Samen met alle andere standaardbewerkingen, onCreate
genereert een exemplaar van de RequestQueue
.
We moeten drie andere methoden implementeren om de helperklasse te voltooien. De eerste methode vervangt Volley.newRequestQueue
, die ik zal noemen getRequestQueue
. We hebben ook een methode nodig om een verzoek aan de wachtrij toe te voegen, toevoegen
, en een methode die verantwoordelijk is voor het annuleren van verzoeken, annuleren
. Het volgende codeblok laat zien hoe de implementatie eruit ziet.
openbare RequestQueue getRequestQueue () return mRequestQueue; openbaarvoid add (Verzoek req) req.setTag (TAG); . GetRequestQueue () toe te voegen (req); public void cancel () mRequestQueue.cancelAll (TAG);
LABEL
is een generiek token dat u gebruikt om het verzoek te identificeren. In dit specifieke geval kan het zijn wat u maar wilt:
openbare statische finale String TAG = MarsWeather.class.getName ();
Zoals u al weet, biedt Volley drie standaard verzoektypen: StringRequest
, ImageRequest
, en JsonRequest
. Onze applicatie gaat deze gebruiken om weergegevens op te halen en de lijst met willekeurige afbeeldingen op te halen.
Standaard stelt Volley de prioriteit van het verzoek in op NORMAL
. Gewoonlijk zou dat goed zijn, maar in onze applicatie hebben we twee verzoeken die heel verschillend zijn en daarom moeten we een andere prioriteit hebben in de wachtrij. Het ophalen van de weergegevens moet een hogere prioriteit hebben dan het ophalen van de URL van de willekeurige afbeelding.
Om die reden moeten we het JsonRequest
klasse. Maak een nieuwe klasse met de naam CustomJsonRequest.java, en zorg dat het uitsteekt JsonObjectRequest
. Behandel vervolgens de getPriority
methode zoals hieronder getoond.
public class CustomJsonRequest breidt JsonObjectRequest uit public CustomJsonRequest (int-methode, String-URL, JSONObject jsonRequest, Response.Listenerlistener, Response.ErrorListener errorListener) super (methode, url, jsonRequest, listener, errorListener); private Priority mPriority; public void setPriority (Priority priority) mPriority = priority; @Override public Priority getPriority () return mPriority == null? Priority.NORMAL: mPriority;
We zijn eindelijk aangekomen bij het meest interessante deel van deze tutorial waarin we de implementatie schrijven om de weergegevens op te halen. Het eindpunt van het verzoek is:
http://marsweather.ingenology.com/v1/latest/
De API's zijn doorzoekbaar, dus open de link om de resulterende JSON te inspecteren. De JSON bevat een eenvoudig object, resultaat
, dat omvat een reeks snaren, variërend van temperatuur tot windrichting en zonsondergangtijd.
Begin met het declareren van de volgende variabelen in de Hoofdactiviteit
klasse:
TextView mTxtDegrees, mTxtWeather, mTxtError; MarsWeather-helper = MarsWeather.getInstance (); laatste statische snaar RECENT_API_ENDPOINT = "http://marsweather.ingenology.com/v1/latest/";
Je kan bellen MarsWeather.getInstance
buiten onCreate
. Aangezien de klasse al is geïnitialiseerd, hoeft u niet te wachten op de onStart
methode om het te noemen. Natuurlijk moet je de referenties van de gebruikersinterface-views instellende onCreate
methode.
mTxtDegrees = (TextView) findViewById (R.id.degrees); mTxtWeather = (TextView) findViewById (R.id.weather); mTxtError = (TextView) findViewById (R.id.error);
Nadat je dat gedaan hebt, is het tijd om het te implementeren loadWeatherData
methode. We maken een aangepast Volley-verzoek en stellen de prioriteit in HIGH
. We roepen vervolgens de helper's aan toevoegen
methode om het aan de wachtrij toe te voegen. Het belangrijkste om op te merken is de luisteraar voor het resultaat, omdat dit de gebruikersinterface zal beïnvloeden.
private void loadWeatherData () CustomJsonRequest request = new CustomJsonRequest (Request.Method.GET, RECENT_API_ENDPOINT, null, new Response.Listener() @Override public void onResponse (JSONObject-respons) try String minTemp, maxTemp, atmo; int avgTemp; response = response.getJSONObject ("rapport"); minTemp = response.getString ("min_temp"); minTemp = minTemp.substring (0, minTemp.indexOf (".")); maxTemp = response.getString ("max_temp"); maxTemp = maxTemp.substring (0, maxTemp.indexOf (".")); avgTemp = (Integer.parseInt (minTemp) + Integer.parseInt (maxTemp)) / 2; atmo = response.getString ("atmo_opacity"); mTxtDegrees.setText (avgTemp + "°"); mTxtWeather.setText (atmo); catch (Uitzondering e) txtError (e); , nieuwe Response.ErrorListener () @Override public void onErrorResponse (VolleyError error) txtError (error); ); request.setPriority (Request.Priority.HIGH); helper.add (verzoek);
Zoals u kunt zien, neemt de methode de minimum- en maximumtemperatuur, berekent het de gemiddelde temperatuur en werkt de gebruikersinterface bij. Ik heb ook een eenvoudige methode geïmplementeerd om fouten af te handelen.
private void txtError (Uitzondering e) mTxtError.setVisibility (View.VISIBLE); e.printStackTrace ();
We hoeven nu alleen nog maar te bellen loadWeatherData
in onCreate
en je bent klaar. De app is nu klaar om het weer van Mars te laten zien.
Nu u de kern van de app klaar en werkzaam heeft, kunnen we ons concentreren op het visueel aantrekkelijker maken van de app. We gaan dit doen door een willekeurig Mars-beeld op te halen en aan de gebruiker te tonen.
U hebt een Flickr API-sleutel nodig om een willekeurige lijst met geconvertualiseerde afbeeldingen op te halen. Het eindpunt van de afbeelding is de volgende:
https://api.flickr.com/services/rest/?format=json&nojsoncallback=1& sort = random & method = flickr.photos.search & tags = mars, planet, rover & tag_mode = all & api_key = [YOUR_KEY]
Zoals u kunt zien, is het verzoek vrij eenvoudig. U vertelt Flickr om u resultaten te geven die zijn geformatteerd als JSON (format = json
), maar we specificeren geen JSON-callback (nojsoncallback = 1
). U zoekt een afbeelding (Werkwijze = flickr.photos.search
) en de tags waarin u bent geïnteresseerd hebben te maken met Mars (labels = mars, planet, rover
). Bekijk de documentatie voor meer informatie over de indeling van de aanvraag-URL.
Begin met het declareren van de volgende variabelen:
laatste statische tekenreeks FLICKR_API_KEY = "[VOEG HIER UW API-SLEUTEL IN]", IMAGES_API_ENDPOINT = "https://api.flickr.com/services/rest/?format=json&nojsoncallback=1&sort=random&method=flickr.photos.search&" + "tags = mars, planet, rover & tag_mode = all & api_key = ";
Implementeer vervolgens de searchRandomImage
methode:
private void searchRandomImage () gooit Exception if (FLICKR_API_KEY.equals ("")) gooit nieuwe uitzondering ("Je hebt geen werkende Flickr API!"); CustomJsonRequest request = new CustomJsonRequest (Request.Method.GET, IMAGES_API_ENDPOINT + FLICKR_API_KEY, null, nieuwe Response.Listener() @Override public void onResponse (JSONObject-respons) try JSONArray images = response.getJSONObject ("photos"). GetJSONArray ("photo"); int index = nieuw Willekeurig (). nextInt (images.length ()); JSONObject imageItem = images.getJSONObject (index); String imageUrl = "http: // farm" + imageItem.getString ("farm") + ".static.flickr.com /" + imageItem.getString ("server") + "/" + imageItem.getString ("id" ) + "_" + imageItem.getString ("secret") + "_" + "c.jpg"; // TODO: doe iets met * imageUrl * catch (Uitzondering e) imageError (e); , nieuwe Response.ErrorListener () @Override public void onErrorResponse (VolleyError error) imageError (error); ); request.setPriority (Request.Priority.LOW); helper.add (verzoek);
Zoals je ziet, stuurt Flickr een a terug JSONArray
met de afbeeldingen. De methode die ik schreef om een willekeurige afbeelding op te halen, genereert een willekeurig getal tussen nul en de grootte van de array. Het neemt het item dat overeenkomt met die index uit de reeks resultaten en construeert de URL voor de afbeelding volgens deze richtlijnen.
Net als voorheen hebben we een methode nodig voor het afhandelen van fouten:
int mainColor = Color.parseColor ("# FF5722"); private void imageError (Uitzondering e) mImageView.setBackgroundColor (mainColor); e.printStackTrace ();
Tot slot, bel searchRandomImage
in de onCreate
methode en vergeet niet om uitzonderingen te vangen.
Nu we een URL hebben om te laden, kunnen we de afbeelding laten zien. Je hebt al geleerd hoe je dit in het vorige artikel moet doen.
private void loadImg (String imageUrl) // Haalt een afbeelding op die is opgegeven door de URL en geeft deze weer in de UI ImageRequest-opdracht = new ImageRequest (imageUrl, nieuwe Response.Listener() @Override public void onResponse (Bitmap bitmap) mImageView.setImageBitmap (bitmap); , 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, new Response.ErrorListener () public void onErrorResponse (VolleyError error) imageError (error); ); // we hoeven hier niet de prioriteit in te stellen; // ImageRequest komt al binnen met // prioriteit ingesteld op LAAG, dat is precies wat we nodig hebben. helper.add (verzoek);
In de onResponse
methode die we in de vorige stap schreven, we zijn eindelijk in staat om het resultaat af te handelen.
loadImg (imageurl);
Misschien heb je al gemerkt dat we het caching-systeem van Volley omzeilen door een willekeurige afbeelding te halen telkens wanneer de toepassing wordt gestart. We moeten een manier vinden om dezelfde afbeelding op een bepaalde dag weer te geven.
De eenvoudigste manier om dit te bereiken is door Android's te gebruiken Gedeelde voorkeuren
. Begin met het declareren van de variabelen die we hiervoor nodig hebben.
SharedPreferences mSharedPref; int today = Calendar.getInstance (). get (Calendar.DAY_OF_MONTH); laatste statische String SHARED_PREFS_IMG_KEY = "img", SHARED_PREFS_DAY_KEY = "dag";
Vervolgens, in de onCreate
methode, vóór de oproep naar searchRandomImage
, initialiseren mSharedPref
.
mSharedPref = getPreferences (Context.MODE_PRIVATE);
Het idee is om de huidige dag op te slaan elke keer dat we een nieuwe willekeurige foto ophalen. Natuurlijk slaan we de URL van de afbeelding naast de dag op. Wanneer de toepassing wordt gestart, controleren we of we al een item hebben in de Gedeelde voorkeuren
voor de huidige dag. Als we een overeenkomst hebben, gebruiken we de opgeslagen URL. Anders halen we een willekeurige afbeelding op en slaan we de URL op in de Gedeelde voorkeuren
.
In searchRandomImage
, na de definitie van afbeelding URL
, voeg de volgende regels toe:
// direct na * String imageUrl = ... * // sla de afbeelding op van de dag SharedPreferences.Editor editor = mSharedPref.edit (); editor.putInt (SHARED_PREFS_DAY_KEY, vandaag); editor.putString (SHARED_PREFS_IMG_KEY, imageUrl); editor.commit (); // en dan is er * loadImage (imageUrl); *
De onCreate
methode, na de definitie op mSharedPref
, wordt nu:
if (mSharedPref.getInt (SHARED_PREFS_DAY_KEY, 0)! = vandaag) // zoek en laad een willekeurige mars pict try searchRandomImage (); catch (Uitzondering e) // vergeet niet om uw eigen Flickr API in te stellen! // anders zal ik // een willekeurige Mars-afbeelding imageRror (e) niet kunnen tonen; else // we hebben al een foto van de dag: laten we laden loadImg (mSharedPref.getString (SHARED_PREFS_IMG_KEY, "")); loadWeatherData ();
Dat is het. Uw aanvraag isklaar. Download de bronbestanden van deze tutorial op GitHub om het voltooide project te bekijken. Bekijk het project als je problemen tegenkomt.
Het lettertype dat in een gebruikersinterface wordt gebruikt, bepaalt vaak het uiterlijk van een toepassing. Laten we beginnen met het wijzigen van het standaard Roboto-lettertype met een aantrekkelijker lettertype, zoals Lato-licht.
Maak een nieuwe map met de naam fonts in de middelen map. Als u de. Niet kunt vinden middelen map, moet u deze op hetzelfde niveau maken als de Java map. De mappenstructuur zou er ongeveer zo uit moeten zien app \ src \ main \ activa \ fonts.
Kopieer het bestand Lato-light.ttf in de fonts map. In de onCreate
methode, moet u het standaardlettertype overschrijven van de weergaven waarin u het nieuwe lettertype wilt gebruiken.
mTxtDegrees.setTypeface (Typeface.createFromAsset (getAssets (), "fonts / Lato-light.ttf")); mTxtWeather.setTypeface (Typeface.createFromAsset (getAssets (), "fonts / Lato-light.ttf"));
Volgens de richtlijnen voor Android Material Design kunnen we de statusbalk transparant maken. Op deze manier zal de achtergrond gedeeltelijk zichtbaar zijn via de statusbalk.
U kunt dit bereiken door een kleine wijziging in het thema van de toepassing aan te brengen. Bewerk de project's v21 \ style.xml bestand als dit:
Zorg ervoor dat de AndroidManifest.xml is al ingesteld om het thema te gebruiken:
We hebben een lange reis gemaakt. In het eerste artikel begonnen we te praten over Volley en zijn toepassingen. In deze zelfstudie hebben we gekeken naar een praktische manier om de concepten die we hebben geleerd te implementeren door een weerapplicatie voor Mars te bouwen. U moet nu een goed begrip hebben van de bibliotheek van Volley, hoe deze werkt en waarvoor u deze kunt gebruiken.