Retrofit è un client HTTP sicuro per tipo per Android e Java. Retrofit semplifica la connessione a un servizio Web REST traducendo l'API in interfacce Java. In questo tutorial, ti mostrerò come utilizzare una delle librerie HTTP più popolari e spesso raccomandate disponibili per Android.
Questa potente libreria semplifica il consumo di dati JSON o XML che vengono poi analizzati in Plain Old Java Objects (POJO). OTTENERE
, INVIARE
, METTERE
, PATCH
, e ELIMINA
le richieste possono essere tutte eseguite.
Come la maggior parte dei software open source, Retrofit è stato costruito su altre potenti librerie e strumenti. Dietro le quinte, Retrofit utilizza OkHttp (dello stesso sviluppatore) per gestire le richieste di rete. Inoltre, Retrofit non ha un convertitore JSON integrato per l'analisi da oggetti JSON a Java. Porta invece il supporto per le seguenti librerie di convertitori JSON per gestire ciò:
com.squareup.retrofit: convertitore-GSON
com.squareup.retrofit: convertitore-jackson
com.squareup.retrofit: convertitore-moshi
Per i buffer di protocollo, i supporti di retrofit:
com.squareup.retrofit2: convertitore-protobuf
com.squareup.retrofit2: convertitore fili
E per XML, Retrofit supporta:
com.squareup.retrofit2: convertitore-simpleframework
Sviluppare la propria libreria HTTP sicura per l'interfaccia con un'API REST può essere un vero problema: è necessario gestire molte funzionalità come effettuare connessioni, memorizzazione nella cache, riprovare richieste non riuscite, threading, analisi delle risposte, gestione degli errori e altro. Il retrofit, d'altra parte, è molto ben pianificato, documentato e testato, una libreria testata in battaglia che ti farà risparmiare un sacco di tempo prezioso e mal di testa.
In questo tutorial, spiegherò come utilizzare Retrofit 2 per gestire le richieste di rete creando una semplice app per interrogare risposte recenti dall'API di Stack Exchange. Ci esibiremo OTTENERE
richieste specificando un endpoint-/ risposte
, aggiunto all'URL di base https://api.stackexchange.com/2.2/- ottenere i risultati e visualizzarli in una visualizzazione di riciclaggio. Ti mostrerò anche come farlo con RxJava per una facile gestione del flusso di stato e dei dati.
Avvia Android Studio e crea un nuovo progetto con un'attività vuota chiamata Attività principale
.
Dopo aver creato un nuovo progetto, dichiara le seguenti dipendenze nel tuo build.gradle
. Le dipendenze includono una vista riciclatore, la libreria Retrofit e anche la libreria Gson di Google per convertire JSON in POJO (Plain Old Java Objects) e l'integrazione di Gof Retrofit.
// Retrofit compile 'com.squareup.retrofit2: retrofit: 2.1.0' // JSON Parsing compile 'com.google.code.gson: gson: 2.6.1' compile 'com.squareup.retrofit2: convertitore-gson: 2.1 .0 '// recyclerview compile' com.android.support:recyclerview-v7:25.0.1 '
Non dimenticare di sincronizzare il progetto per scaricare queste librerie.
Per eseguire operazioni di rete, è necessario includere il INTERNET
permesso nel manifest dell'applicazione: AndroidManifest.xml.
Creeremo automaticamente i nostri modelli dai nostri dati di risposta JSON sfruttando uno strumento molto utile: jsonschema2pojo.
Copia e incolla https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow nella barra degli indirizzi del tuo browser (oppure potresti usare Postman se conosci questo strumento). Quindi premere accedere-questo eseguirà una richiesta GET sull'endpoint specificato. Quello che vedrai in risposta è un array di oggetti JSON. Lo screenshot seguente è la risposta JSON che utilizza Postman.
"items": ["owner": "reputation": 1, "user_id": 6540831, "user_type": "registered", "profile_image": "https://www.gravatar.com/avatar/6a468ce8a8ff42c17923a6009ab77723 ? s = 128 & d = identicon & r = PG & f = 1 "," display_name ":" bobolafrite "," link ":" http://stackoverflow.com/users/6540831/bobolafrite "," is_accepted ": false," punteggio " : 0, "last_activity_date": 1480862271, "creation_date": 1480862271, "answer_id": 40959732, "question_id": 35931342, "owner": "reputation": 629, "user_id": 3054722, "user_type": "registered", "profile_image": "https://www.gravatar.com/avatar/0cf65651ae9a3ba2858ef0d0a7dbf900?s=128&d=identicon&r=PG&f=1", "display_name": "jeremy-denis", "link": "http : //stackoverflow.com/users/3054722/jeremy-denis "," is_accepted ": false," score ": 0," last_activity_date ": 1480862260," creation_date ": 1480862260," answer_id ": 40959731," question_id " : 40959661, ...], "has_more": true, "backoff": 10, "quota_max": 300, "quota_remaining": 241
Copia questa risposta JSON dal tuo browser o Postman.
Ora visita jsonschema2pojo e incolla la risposta JSON nella casella di input.
Seleziona un tipo di fonte di JSON, stile di annotazione di GSON, e deselezionare Consenti proprietà aggiuntive.
Quindi fare clic su Anteprima pulsante per generare gli oggetti Java.
Potresti chiederti che cosa @SerializedName
e @Esporre
le annotazioni fanno in questo codice generato. Non preoccuparti, ti spiegherò tutto!
Il @SerializedName
l'annotazione è necessaria per Gson per mappare le chiavi JSON con i nostri campi. In linea con la convenzione di denominazione CamelCase di Java per le proprietà dei membri della classe, non è consigliabile utilizzare caratteri di sottolineatura per separare le parole in una variabile. @SerializedName
aiuta a tradurre tra i due.
@SerializedName ("quota_remaining") @Expose private Integer quotaRemaining;
Nell'esempio sopra, stiamo dicendo a Gson che la nostra chiave JSON quota_remaining
dovrebbe essere mappato al campo Java quotaRemaining
. Se entrambi questi valori erano uguali, cioè se la nostra chiave JSON era quotaRemaining
proprio come il campo Java, quindi non ci sarebbe bisogno di @SerializedName
annotazione sul campo perché Gson li mapperebbe automaticamente.
Il @Esporre
l'annotazione indica che questo membro deve essere esposto per la serializzazione o deserializzazione JSON.
Ora torniamo ad Android Studio. Crea un nuovo sotto-pacchetto all'interno del pacchetto principale e nominalo dati. All'interno del pacchetto dati appena creato, crea un altro pacchetto e chiamalo modello. All'interno del pacchetto del modello, creare una nuova classe Java e denominarla Proprietario
. Ora copia il Proprietario
classe che è stata generata da jsonschema2pojo e incollarla all'interno di Proprietario
classe che hai creato.
import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; Proprietario di classe pubblica @SerializedName ("reputation") @Expose private Integer reputation; @SerializedName ("user_id") @Expose Private Integer userId; @SerializedName ("user_type") @Expose private String userType; @SerializedName ("profile_image") @Expose private String profileImage; @SerializedName ("display_name") @Expose private String displayName; @SerializedName ("link") @Expose private String link; @SerializedName ("accept_rate") @Expose private Integer acceptRate; public Integer getReputation () return reputation; public void setReputation (Integer reputation) this.reputation = reputation; public Integer getUserId () return userId; public void setUserId (Integer userId) this.userId = userId; public String getUserType () return userType; public void setUserType (String userType) this.userType = userType; public String getProfileImage () return profileImage; public void setProfileImage (String profileImage) this.profileImage = profileImage; public String getDisplayName () return displayName; public void setDisplayName (String displayName) this.displayName = displayName; public String getLink () return link; public void setLink (String link) this.link = link; public Integer getAcceptRate () return acceptRate; public void setAcceptRate (Integer acceptRate) this.acceptRate = acceptRate;
Fai la stessa cosa per un nuovo Articolo
classe, copiata da jsonschema2pojo.
import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; Articolo di classe pubblica @SerializedName ("owner") @Expose private Owner owner; @SerializedName ("is_accepted") @Expose Boolean privato isAccepted; @SerializedName ("score") @Expose private Integer score; @SerializedName ("last_activity_date") @Expose Integer privato lastActivityDate; @SerializedName ("creation_date") @Expose Private Integer creationDate; @SerializedName ("answer_id") @Expose Private Integer answerId; @SerializedName ("question_id") @Expose Intero privato questionId; @SerializedName ("last_edit_date") @Expose Intero privato lastEditDate; proprietario pubblico getOwner () return owner; public void setOwner (proprietario proprietario) this.owner = owner; public Boolean getIsAccepted () return isAccepted; public void setIsAccepted (Boolean isAccepted) this.isAccepted = isAccepted; public Integer getScore () return score; public void setScore (Integer score) this.score = score; public Integer getLastActivityDate () return lastActivityDate; public void setLastActivityDate (Integer lastActivityDate) this.lastActivityDate = lastActivityDate; public Integer getCreationDate () return creationDate; public void setCreationDate (Integer creationDate) this.creationDate = creationDate; public Intero getAnswerId () return ID di risposta; public void setAnswerId (Integer answerId) this.answerId = answerId; public Integer getQuestionId () return QuestionId; public void setQuestionId (Interiger questionId) this.questionId = questionId; public Integer getLastEditDate () return lastEditDate; public void setLastEditDate (Integer lastEditDate) this.lastEditDate = lastEditDate;
Infine, crea una classe chiamataSOAnswersResponse
per le risposte StackOverflow restituite. Troverai il codice per questa classe in jsonschema2pojo come Esempio
. Assicurati di aggiornare il nome della classe su SOAnswersResponse
ovunque si verifichi.
import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import java.util.List; public class SOAnswersResponse @SerializedName ("items") @Expose private List- items = null; @SerializedName ("has_more") @Expose Boolean privato hasMore; @SerializedName ("backoff") @Expose backoff Intero privato; @SerializedName ("quota_max") @Expose intero Numero intero quotaMax; @SerializedName ("quota_remaining") @Expose private Integer quotaRemaining; lista pubblica
- getItems () return items; setItems vuoto pubblico (Elenco
- articoli) this.items = articoli; public Boolean getHasMore () return hasMore; public void setHasMore (Boolean hasMore) this.hasMore = hasMore; public Intero getBackoff () return backoff; public void setBackoff (Integer backoff) this.backoff = backoff; public Intero getQuotaMax () return quotaMax; public void setQuotaMax (Integer quotaMax) this.quotaMax = quotaMax; public Intero getQuotaRemaining () return quotaRemaining; public void setQuotaRemaining (Integer quotaRemaining) this.quotaRemaining = quotaRemaining;
Per inviare richieste di rete a un'API REST con Retrofit, dobbiamo creare un'istanza usando il Retrofit.Builder
classe e configurarlo con un URL di base.
Crea un nuovo pacchetto sub-pacchetto all'interno del dati
pacchetto e chiamarlo a distanza
. Ora dentro a distanza
, creare una classe Java e nominarla RetrofitClient
. Questa classe creerà un singleton di Retrofit. Il retrofit richiede un URL di base per creare la sua istanza, quindi passeremo un URL quando chiameremo RetrofitClient.getClient (String baseUrl)
. Questo URL verrà quindi utilizzato per creare l'istanza nella riga 13. Stiamo anche specificando il convertitore JSON di cui abbiamo bisogno (Gson) nella riga 14.
importazione retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class RetrofitClient retrofit statico privato retrofit = null; public static Retrofit getClient (String baseUrl) if (retrofit == null) retrofit = new Retrofit.Builder () .baseUrl (baseUrl) .addConverterFactory (GsonConverterFactory.create ()) .build (); retrofit di ritorno;
All'interno del pacchetto remoto, crea un'interfaccia e chiamala SOService
. Questa interfaccia contiene metodi che utilizzeremo per eseguire richieste HTTP come OTTENERE
, INVIARE
, METTERE
, PATCH
, e ELIMINA
. Per questo tutorial, stiamo per eseguire a OTTENERE
richiesta.
import com.chikeandroid.retrofittutorial.data.model.SOAnswersResponse; import java.util.List; import retrofit2.Call; import retrofit2.http.GET; interfaccia pubblica SOService @GET ("/ risposte? order = desc & sort = activity & site = stackoverflow") ChiamagetAnswers (); @GET ("/ risponde? Order = desc & sort = activity & site = stackoverflow") Chiama getAnswers (@Query ("tagged") Tag delle stringhe);
Il @OTTENERE
l'annotazione lo definisce esplicitamente OTTENERE
richiesta che verrà eseguita una volta chiamato il metodo. Ogni metodo in questa interfaccia deve avere un'annotazione HTTP che fornisce il metodo di richiesta e l'URL relativo. Sono disponibili cinque annotazioni integrate: @OTTENERE
, @INVIARE
, @METTERE
, @ELIMINA
, e @CAPO
.
Nella seconda definizione del metodo, abbiamo aggiunto un parametro di query per filtrare i dati dal server. Il retrofit ha il @ Query ( "chiave")
annotazione da utilizzare invece di codificarla nel punto finale. Il valore della chiave rappresenta il nome del parametro nell'URL. Sarà aggiunto all'URL di Retrofit. Ad esempio, se passiamo il valore "Android"
come argomento per il getAnswers (tag delle stringhe)
metodo, l'URL completo sarà:
https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow&tagged=android
I parametri dei metodi di interfaccia possono avere le seguenti annotazioni:
@Sentiero | sostituzione variabile per l'endpoint API |
@query | specifica il nome della chiave della query con il valore del parametro annotato |
@Corpo | carico utile per la chiamata POST |
@Intestazione | specifica l'intestazione con il valore del parametro annotato |
Ora creeremo una classe di utilità. Lo nomineremo ApiUtils
. Questa classe avrà l'URL di base come variabile statica e fornirà anche il SOService
interfaccia alla nostra applicazione attraverso il getSOService ()
metodo statico.
public class ApiUtils public static final String BASE_URL = "https://api.stackexchange.com/2.2/"; public static SOService getSOService () return RetrofitClient.getClient (BASE_URL) .create (SOService.class);
Poiché i risultati verranno visualizzati in una visualizzazione di riciclaggio, abbiamo bisogno di un adattatore. Il seguente frammento di codice mostra il AnswersAdapter
classe.
classe pubblica AnswersAdapter estende RecyclerView.AdapterLista privata - mItems; contesto privato mContext; PostItemListener privato mItemListener; public class ViewHolder estende RecyclerView.ViewHolder implementa View.OnClickListener public TextView titleTv; PostItemListener mItemListener; public ViewHolder (Visualizza itemView, PostItemListener postItemListener) super (itemView); titleTv = (TextView) itemView.findViewById (android.R.id.text1); this.mItemListener = postItemListener; itemView.setOnClickListener (questo); @Override public void onClick (Visualizza vista) Item item = getItem (getAdapterPosition ()); this.mItemListener.onPostClick (item.getAnswerId ()); notifyDataSetChanged (); public AnswersAdapter (Contesto contesto, Elenco
- post, PostItemListener itemListener) mItems = posts; mContext = contesto; mItemListener = itemListener; @Override public AnswersAdapter.ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) Context context = parent.getContext (); LayoutInflater inflater = LayoutInflater.from (context); Visualizza postView = inflater.inflate (android.R.layout.simple_list_item_1, parent, false); ViewHolder viewHolder = new ViewHolder (postView, this.mItemListener); return viewHolder; @Override public void onBindViewHolder (AnswersAdapter.ViewHolder holder, int position) Item item = mItems.get (position); TextView textView = holder.titleTv; textView.setText (item.getOwner () getDisplayName ().); @Override public int getItemCount () return mItems.size (); public void updateAnswers (Lista
- items) mItems = items; notifyDataSetChanged (); private Item getItem (int adapterPosition) return mItems.get (adapterPosition); interfaccia pubblica PostItemListener void onPostClick (long id);
Dentro il onCreate ()
metodo del Attività principale
, inizializziamo un'istanza di SOService
interfaccia (riga 9), la vista del riciclatore e anche l'adattatore. Infine, chiamiamo il loadAnswers ()
metodo.
private AnswersAdapter mAdapter; private RecyclerView mRecyclerView; SOService mService privato; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mService = ApiUtils.getSOService (); mRecyclerView = (RecyclerView) findViewById (R.id.rv_answers); mAdapter = new AnswersAdapter (questo, nuovo ArrayList- (0), new AnswersAdapter.PostItemListener () @Override public void onPostClick (long id) Toast.makeText (MainActivity.this, "ID post è" + id, Toast.LENGTH_SHORT) .show (); ); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager (this); mRecyclerView.setLayoutManager (LayoutManager); mRecyclerView.setAdapter (mAdapter); mRecyclerView.setHasFixedSize (true); RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration (this, DividerItemDecoration.VERTICAL_LIST); mRecyclerView.addItemDecoration (itemDecoration); loadAnswers ();
Il loadAnswers ()
metodo effettua una richiesta di rete chiamando enqueue ()
. Quando la risposta ritorna, Retrofit ci aiuta ad analizzare la risposta JSON a un elenco di oggetti Java. (Ciò è reso possibile dall'uso GsonConverter
.)
public void loadAnswers () mService.getAnswers (). enqueue (new Callback() @ Override public void onResponse (Call chiamata, risposta risposta) if (response.isSuccessful ()) mAdapter.updateAnswers (response.body (). getItems ()); Log.d ("MainActivity", "posts loaded from API"); else int statusCode = response.code (); // gestisce gli errori di richiesta in base al codice di stato @Override public void onFailure (Call call, Throwable t) showErrorMessage (); Log.d ("MainActivity", "errore di caricamento da API"); );
enqueue ()
enqueue ()
invia in modo asincrono la richiesta e avvisa la tua app con un callback quando ritorna una risposta. Poiché questa richiesta è asincrona, Retrofit la gestisce su un thread in background in modo che il thread dell'interfaccia utente principale non sia bloccato o interferito con.
Usare enqueue ()
, devi implementare due metodi di callback:
onResponse ()
onFailure ()
Solo uno di questi metodi verrà chiamato in risposta a una determinata richiesta.
onResponse ()
: invocato per una risposta HTTP ricevuta. Questo metodo viene chiamato per una risposta che può essere gestita correttamente anche se il server restituisce un messaggio di errore. Quindi se ottieni un codice di stato 404 o 500, questo metodo verrà comunque chiamato. Per ottenere il codice di stato al fine di gestire le situazioni basate su di essi, è possibile utilizzare il metodo Codice di risposta()
. Puoi anche usare il isSuccessful ()
metodo per scoprire se il codice di stato è nell'intervallo 200-300, indicando il successo.onFailure ()
: richiamato quando si è verificata un'eccezione di rete che comunica al server o quando si è verificata un'eccezione imprevista durante la gestione della richiesta o l'elaborazione della risposta. Per eseguire una richiesta sincrona, è possibile utilizzare il eseguire()
metodo. Tieni presente che i metodi sincroni sul thread principale / dell'interfaccia utente bloccheranno qualsiasi azione dell'utente. Quindi non eseguire metodi sincroni sul thread principale / dell'interfaccia utente di Android! Invece, eseguili su un thread in background.
Ora puoi eseguire l'app.
Se sei un fan di RxJava, puoi facilmente implementare Retrofit con RxJava. In Retrofit 1 è stato integrato per impostazione predefinita, ma in Retrofit 2 è necessario includere alcune dipendenze aggiuntive. Il retrofit viene fornito con un adattatore predefinito per l'esecuzione Chiamata
le istanze. Quindi è possibile modificare il meccanismo di esecuzione di Retrofit per includere RxJava includendo RxJava CallAdapter
.
Aggiungi le dipendenze.
compile 'io.reactivex: rxjava: 1.1.6' compila 'io.reactivex: rxandroid: 1.2.1' compile 'com.squareup.retrofit2: adapter-rxjava: 2.1.0'
Aggiungi il nuovo CallAdapter RxJavaCallAdapterFactory.create ()
quando si costruisce un'istanza di Retrofit.
public static Retrofit getClient (String baseUrl) if (retrofit == null) retrofit = new Retrofit.Builder () .baseUrl (baseUrl) .addCallAdapterFactory (RxJavaCallAdapterFactory.create ()) .addConverterFactory (GsonConverterFactory.create ()) .build (); retrofit di ritorno;
Ora aggiorna il getAnswers ()
metodi per tornare Osservabile
S:
@GET ("/ risponde? Order = desc & sort = activity & site = stackoverflow") OsservabilegetAnswers (); @GET ("/ risponde? Order = desc & sort = activity & site = stackoverflow") Osservabile getAnswers (@Query ("tagged") Tag delle stringhe);
Quando facciamo le richieste, il nostro abbonato anonimo risponde allo stream osservabile che emette eventi, nel nostro caso SOAnswersResponse
. Il onNext
il metodo viene quindi chiamato quando il nostro abbonato riceve qualsiasi evento emesso che viene poi passato al nostro adattatore.
@Override public void loadAnswers () mService.getAnswers (). SubscribeOn (Schedulers.io ()). ObservOn (AndroidSchedulers.mainThread ()) .subscribe (new Subscriber() @Override public void onCompleted () @Override public void onError (Throwable e) @Override public void onNext (SOAnswersResponse soAnswersResponse) mAdapter.updateAnswers (soAnswersResponse.getItems ()); );
Scopri come iniziare con ReactiveX su Android di Ashraff Hathibelagal per saperne di più su RxJava e RxAndroid.
In questo tutorial, hai imparato a conoscere Retrofit: perché dovresti usarlo e come. Ho anche spiegato come aggiungere l'integrazione RxJava con Retrofit. Nel mio prossimo post, ti mostrerò come esibirti INVIARE
, METTERE
, e ELIMINA
, come spedire Form-urlencoded
dati e come cancellare le richieste.
Per ulteriori informazioni su Retrofit, fare riferimento alla documentazione ufficiale. E nel frattempo, dai uno sguardo ad alcuni dei nostri altri corsi e tutorial sullo sviluppo di app per Android.