In questo tutorial ti mostrerò un possibile caso d'uso di ciò che abbiamo imparato nel precedente articolo su Volley. Creeremo un'applicazione meteo per Marte, utilizzando le informazioni raccolte dal rover Curiosity, che è reso disponibile a tutti dalla NASA attraverso l'API MAAS.
Innanzitutto, configureremo il progetto in Android Studio e progetteremo l'interfaccia utente. Quindi struttureremo il nucleo dell'applicazione utilizzando Volley. Poiché ogni bella applicazione presenta alcune immagini, ti mostrerò come recuperarne una a caso usando l'API di Flickr. Scaricheremo l'immagine con Volley, principalmente per il suo ottimo sistema di memorizzazione nella cache. Infine, aggiungeremo alcuni dettagli fantasiosi per conferire all'applicazione un aspetto e una sensazione stupendi.
Innanzitutto, crea un nuovo progetto in Android Studio. Dal momento che Volley è retrocompatibile, puoi scegliere qualsiasi livello API che preferisci. Ho optato per l'API 21, ma dovresti stare bene finché il livello API è 8 (Froyo) o superiore.
La nostra applicazione ha una sola, semplice attività. Puoi chiamarlo MainActivity.java, come suggerito da Android Studio. Apri l'editor di layout e fai doppio clic activity_main.xml.
Dal momento che vorremmo avere circa il 70% dello schermo dedicato all'immagine e il resto alle informazioni meteorologiche, dobbiamo usare l'attributo XML layout_weight
. Certo, possiamo usare anche i valori assoluti, ma non sarebbe lo stesso. Sfortunatamente, il mondo Android presenta display che sono tutt'altro che omogenei, e la specifica di un valore assoluto per l'altezza dell'immagine potrebbe tradursi in un rapporto 90-10 su dispositivi molto piccoli e una relazione 70-30 o anche 60-40, su dispositivi più grandi. Il layout_weight
l'attributo è ciò di cui hai bisogno per risolvere questo problema.
All'interno del primo figlio, aggiungi il ImageView
:
Nel secondo RelativeLayout
, aggiungiamo una lista di TextView
elementi. Due di questi sono viste in cui vengono visualizzate la temperatura media e l'opacità dell'atmosfera. Il terzo è un'etichetta di errore.
Il layout dovrebbe ora essere completo. È possibile aggiungere ulteriori dettagli se lo si desidera, ma un'interfaccia utente complessa e dettagliata non rientra nell'ambito di questo tutorial.
Ci sono altre due cose di cui dobbiamo occuparci prima di iniziare a scavare nel nucleo dell'applicazione. Cambia il tema ereditato dell'applicazione in Android: Theme.Material.Light.NoActionBar
. Ciò significa che non è necessario nascondere la barra delle azioni in fase di esecuzione.
Infine, aggiungi l'autorizzazione Internet al manifest del progetto.
Come abbiamo discusso nel precedente articolo, il modo più semplice e affidabile per usare Volley è importare la libreria come un nuovo modulo. Scarica il codice sorgente della libreria, importalo tramite File > Nuovo > Modulo, e dire al compilatore nel progetto build.gradle file per includerlo nel progetto.
progetto di compilazione (": volley")
Come ho già indicato nell'articolo precedente, se è necessario attivare più richieste, è preferibile utilizzare una coda di richieste condivisa. Dovresti evitare di creare una coda di richieste ogni volta che pianifichi una richiesta invocando Volley.newRequestQueue
, perché non vuoi finire con perdite di memoria e altri problemi indesiderati.
Per fare ciò, devi prima creare una classe usando il modello singleton. La classe viene referenziata usando una variabile statica, visibile a livello globale, che quindi gestisce l'oggetto RequestQueue
. In questo modo, si finisce con un singolo RequestQueue
per l'applicazione. Quindi, estendendo il Applicazione
classe, devi dire al sistema operativo di generare questo oggetto all'avvio dell'applicazione, anche prima che venga creata la prima attività.
Dato che siamo nell'ambiente Android, modifichiamo leggermente la struttura del singleton comune. La classe deve creare una nuova istanza di se stesso nel Application.onCreate
metodo: non in un generico getInstance
metodo quando è nullo
.
Per ottenere ciò, crea una nuova classe e nominala MarsWeather.java. Quindi, estendi l'Android Applicazione
classe, scavalcare il onCreate
metodo e inizializzare il RequestQueue
oggetto dell'istanza statica.
Nella classe singleton, costruiamo l'oggetto della classe usando a pubblico
e sincronizzato
funzione getInstance
. All'interno di questo metodo, restituiamo il mInstance
variabile. Il onCreate
il metodo viene richiamato all'avvio dell'applicazione in modo che mInstance
la variabile sarà già impostata la prima volta getInstance
il metodo è invocato.
classe pubblica MarsWeather estende Application private RequestQueue mRequestQueue; sostanza statica di MarsWeather privata; @Override public void onCreate () super.onCreate (); mInstance = this; mRequestQueue = Volley.newRequestQueue (getApplicationContext ()); public static synchronized MarsWeather getInstance () return mInstance;
Quindi, dillo nel AndroidManifest.xml file che vuoi MarsWeather
da caricare all'avvio dell'applicazione. Nel
tag, aggiungi l'attributo nome
come segue:
android: name = "MarsWeather"
Questo è tutto. Un'istanza del Applicazione
la classe viene creata, anche prima Attività principale
è creato. Insieme a tutte le altre operazioni standard, onCreate
genera un'istanza di RequestQueue
.
Dobbiamo implementare altri tre metodi per completare la classe di supporto. Il primo metodo sostituisce Volley.newRequestQueue
, quale chiamerò getRequestQueue
. Abbiamo anche bisogno di un metodo per aggiungere una richiesta alla coda, Inserisci
, e un metodo che è responsabile per l'annullamento delle richieste, Annulla
. Il seguente blocco di codice mostra come si presenta l'implementazione.
public RequestQueue getRequestQueue () return mRequestQueue; pubblicovoid add (Richiesta req) req.setTag (TAG); . GetRequestQueue () aggiungere (req); public void cancel () mRequestQueue.cancelAll (TAG);
ETICHETTA
è un token generico che usi per identificare la richiesta. In questo caso specifico, può essere quello che vuoi:
public static final String TAG = MarsWeather.class.getName ();
Come già sai, Volley offre tre tipi di richieste standard: StringRequest
, ImageRequest
, e JsonRequest
. La nostra applicazione utilizzerà quest'ultima per recuperare i dati meteorologici e recuperare l'elenco di immagini casuali.
Per impostazione predefinita, Volley imposta la priorità della richiesta a NORMALE
. Di solito andrebbe bene, ma nella nostra applicazione abbiamo due richieste molto diverse e quindi dobbiamo avere una priorità diversa nella coda. Il recupero dei dati meteorologici deve avere una priorità più alta rispetto al recupero dell'URL dell'immagine casuale.
Per questo motivo, abbiamo bisogno di personalizzare il JsonRequest
classe. Crea una nuova classe chiamata CustomJsonRequest.java, e assicurarsi che si estenda JsonObjectRequest
. Quindi, ignora il getPriority
metodo come mostrato di seguito.
public class CustomJsonRequest estende JsonObjectRequest public CustomJsonRequest (metodo int, string URL, JSONObject jsonRequest, Response.Listenerlistener, Response.ErrorListener errorListener) super (metodo, url, jsonRequest, listener, errorListener); private Priority mPriority; public void setPriority (Priorità prioritaria) mPriority = priority; @Override public Priority getPriority () return mPriority == null? Priorità.NORMALE: mPriorità;
Siamo finalmente arrivati alla parte più interessante di questo tutorial in cui scriviamo l'implementazione per recuperare i dati meteorologici. L'endpoint della richiesta è:
http://marsweather.ingenology.com/v1/latest/
Le API sono sfogliabili, quindi apri il link per ispezionare il JSON risultante. Il JSON contiene un oggetto semplice, risultato
, che include una serie di stringhe, che vanno dalla temperatura alla direzione del vento e al tramonto.
Inizia dichiarando le seguenti variabili nel file Attività principale
classe:
TextView mTxtDegrees, mTxtWeather, mTxtError; MarsWeather helper = MarsWeather.getInstance (); stringa statica finale RECENT_API_ENDPOINT = "http://marsweather.ingenology.com/v1/latest/";
Puoi chiamare MarsWeather.getInstance
al di fuori di onCreate
. Poiché la classe sarà già inizializzata, non è necessario attendere il onStart
metodo per chiamarlo. Ovviamente, devi impostare i riferimenti delle viste dell'interfaccia utente inil onCreate
metodo.
mTxtDegrees = (TextView) findViewById (R.id.degrees); mTxtWeather = (TextView) findViewById (R.id.weather); mTxtError = (TextView) findViewById (R.id.error);
Dopo averlo fatto, è il momento di implementare il loadWeatherData
metodo. Creiamo una richiesta Volley personalizzata e impostiamo la priorità su ALTA
. Invochiamo quindi l'aiutante Inserisci
metodo per aggiungerlo alla coda della richiesta. La cosa importante da notare è l'ascoltatore dei risultati, poiché influenzerà l'interfaccia utente.
private void loadWeatherData () CustomJsonRequest request = new CustomJsonRequest (Request.Method.GET, RECENT_API_ENDPOINT, null, new Response.Listener() @ Override public onResponse (risposta JSONObject) try String minTemp, maxTemp, atmo; int avgTemp; response = response.getJSONObject ("report"); 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 (Exception e) txtError (e); , new Response.ErrorListener () @Override public void onErrorResponse (VolleyError error) txtError (errore); ); request.setPriority (Request.Priority.HIGH); helper.add (richiesta);
Come puoi vedere, il metodo prende le temperature minime e massime, calcola la temperatura media e aggiorna l'interfaccia utente. Ho anche implementato un metodo semplice per gestire gli errori.
private void txtError (Exception e) mTxtError.setVisibility (View.VISIBLE); e.printStackTrace ();
Ora dobbiamo solo chiamare loadWeatherData
nel onCreate
e hai finito. L'app è ora pronta per mostrare il tempo di Marte.
Ora che hai il nucleo dell'app pronta e funzionante, possiamo concentrarci sul rendere l'app visivamente più attraente. Lo faremo recuperando un'immagine Mars casuale e mostrandola all'utente.
Avrai bisogno di una chiave API Flickr per recuperare un elenco casuale di immagini contestualizzate. L'endpoint dell'immagine è il seguente:
https://api.flickr.com/services/rest/?format=json&nojsoncallback=1& sort = random & method = flickr.photos.search & tags = mars, planet, rover e tag_mode = all & api_key = [YOUR_KEY]
Come puoi vedere, la richiesta è abbastanza semplice. Stai dicendo a Flickr di darti risultati formattati come JSON (format = json
), ma non specifichiamo un callback JSON (nojsoncallback = 1
). Stai cercando un'immagine (method = flickr.photos.search
) e i tag che ti interessano sono correlati a Marte (tags = Marte, pianeta, rover
). Dai un'occhiata alla documentazione per maggiori informazioni sul formato dell'URL della richiesta.
Inizia dichiarando le seguenti variabili:
stringa statica finale FLICKR_API_KEY = "[INSERIRE QUI LA TUA API KEY]", IMAGES_API_ENDPOINT = "https://api.flickr.com/services/rest/?format=json&nojsoncallback=1&sort=random&method=flickr.photos.search&" + "tags = Marte, pianeta, rover & tag_mode = all & api_key = ";
Quindi, implementare il searchRandomImage
metodo:
private void searchRandomImage () genera Exception if (FLICKR_API_KEY.equals ("")) lancia una nuova Exception ("Non hai fornito un'API Flickr funzionante!"); CustomJsonRequest request = new CustomJsonRequest (Request.Method.GET, IMAGES_API_ENDPOINT + FLICKR_API_KEY, null, new Response.Listener() @ Override public onResponse (risposta JSONObject) try JSONArray images = response.getJSONObject ("photos"). GetJSONArray ("photo"); int index = new Random (). 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: fare qualcosa con * imageUrl * catch (Exception e) imageError (e); , new Response.ErrorListener () @Override public void onErrorResponse (VolleyError error) imageError (errore); ); request.setPriority (Request.Priority.LOW); helper.add (richiesta);
Come puoi vedere, Flickr rimanda a JSONArray
contenente le immagini. Il metodo che ho scritto per recuperare un'immagine casuale genera un numero casuale compreso tra zero e la dimensione dell'array. Prende l'elemento corrispondente a quell'indice dalla serie di risultati e costruisce l'URL per l'immagine seguendo queste linee guida.
Come prima, abbiamo bisogno di un metodo per la gestione degli errori:
int mainColor = Color.parseColor ("# FF5722"); private void imageError (Exception e) mImageView.setBackgroundColor (mainColor); e.printStackTrace ();
Infine, chiama searchRandomImage
nel onCreate
metodo e non dimenticare di rilevare eccezioni.
Ora che abbiamo un URL da caricare, possiamo mostrare l'immagine. Hai già imparato come farlo nel precedente articolo.
private void loadImg (String imageUrl) // Recupera un'immagine specificata dall'URL e la visualizza nell'interfaccia utente Richiesta ImageRequest = new ImageRequest (imageUrl, new 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 (Errore VolleyError) imageError (errore); ); // non abbiamo bisogno di impostare la priorità qui; // ImageRequest giunge già con // priorità impostata su LOW, questo è esattamente ciò di cui abbiamo bisogno. helper.add (richiesta);
Nel onResponse
metodo che abbiamo scritto nel passaggio precedente, siamo finalmente in grado di gestire il risultato.
loadImg (URL dell'immagine);
Forse hai già notato che stiamo bypassando il sistema di caching di Volley recuperando un'immagine casuale ogni volta che l'applicazione viene lanciata. Dobbiamo trovare un modo per mostrare la stessa immagine in un giorno particolare.
Il modo più semplice per raggiungere questo obiettivo è utilizzare Android SharedPreferences
. Inizia dichiarando le variabili di cui avremo bisogno per questo.
SharedPreferences mSharedPref; int today = Calendar.getInstance (). get (Calendar.DAY_OF_MONTH); stringa statica finale SHARED_PREFS_IMG_KEY = "img", SHARED_PREFS_DAY_KEY = "giorno";
Successivamente, nel onCreate
metodo, prima della chiamata a searchRandomImage
, inizializzare mSharedPref
.
mSharedPref = getPreferences (Context.MODE_PRIVATE);
L'idea è di memorizzare il giorno corrente ogni volta che recuperiamo una nuova immagine casuale. Ovviamente, archiviamo l'URL dell'immagine accanto al giorno. Quando l'applicazione si avvia, controlliamo se abbiamo già una voce nel SharedPreferences
per il giorno corrente. Se abbiamo una corrispondenza, usiamo l'URL memorizzato. Altrimenti recuperiamo un'immagine casuale e memorizziamo il suo URL nel SharedPreferences
.
Nel searchRandomImage
, dopo la definizione di URL dell'immagine
, aggiungi le seguenti righe di codice:
// subito dopo * String imageUrl = ... * // memorizza l'immagine del giorno SharedPreferences.Editor editor = mSharedPref.edit (); editor.putInt (SHARED_PREFS_DAY_KEY, oggi); editor.putString (SHARED_PREFS_IMG_KEY, imageUrl); editor.commit (); // e poi c'è * loadImage (imageUrl); *
Il onCreate
metodo, dopo la definizione su mSharedPref
, ora diventa:
if (mSharedPref.getInt (SHARED_PREFS_DAY_KEY, 0)! = today) // cerca e carica un mars mars a caso prova searchRandomImage (); catch (Exception e) // Ricordati di impostare la tua API Flickr! // altrimenti non sarò in grado di mostrare // un'immagine di Mars casuale imageError (e); else // abbiamo già un pict del giorno: carichiamolo loadImg (mSharedPref.getString (SHARED_PREFS_IMG_KEY, "")); loadWeatherData ();
Questo è tutto. La tua domanda èpronto. Sentiti libero di scaricare i file sorgente di questo tutorial su GitHub per vedere il progetto completato. Dai un'occhiata al progetto se stai riscontrando problemi.
Il carattere utilizzato in un'interfaccia utente spesso determina l'aspetto di un'applicazione. Iniziamo cambiando il carattere predefinito di Roboto con un font più accattivante, come Lato light.
Crea una nuova cartella chiamata font nel risorse cartella. Se non riesci a trovare il risorse cartella, devi crearlo allo stesso livello di Giava cartella. La struttura della cartella dovrebbe essere simile app \ src \ principali beni \ \ fonts.
Copia il file Lato-light.ttf nel font cartella. Nel onCreate
metodo, è necessario sovrascrivere il carattere tipografico predefinito delle viste in cui si desidera utilizzare il nuovo carattere.
mTxtDegrees.setTypeface (Typeface.createFromAsset (getAssets (), "fonts / Lato-light.ttf")); mTxtWeather.setTypeface (Typeface.createFromAsset (getAssets (), "fonts / Lato-light.ttf"));
Seguendo le linee guida per Android Material Design, possiamo rendere trasparente la barra di stato. In questo modo, lo sfondo sarà parzialmente visibile attraverso la barra di stato.
È possibile ottenere questo facendo una piccola modifica nel tema dell'applicazione. Modifica il progetto v21 \ style.xml file come questo:
Assicurarsi che il AndroidManifest.xml è già impostato per utilizzare il tema:
Abbiamo fatto un lungo viaggio. Nel primo articolo, abbiamo iniziato a parlare di Volley e delle sue applicazioni. In questo tutorial, abbiamo esaminato un modo pratico per implementare i concetti che abbiamo appreso costruendo un'applicazione meteo per Marte. Dovresti ora avere una buona conoscenza della libreria di Volley, di come funziona e di cosa puoi usare per.