Retrofit este un client HTTP sigur pentru aplicații Android și Java. Retrofit-ul facilitează conectarea la un serviciu Web REST prin traducerea API-ului în interfețe Java. În acest tutorial, vă vom arăta cum să utilizați una dintre cele mai populare și adesea recomandate biblioteci HTTP disponibile pentru Android.
Această bibliotecă puternică facilitează consumarea datelor JSON sau XML care sunt apoi analizate în obiecte obișnuite Java vechi (POJOs). OBȚINE
, POST
, A PUNE
, PLASTURE
, și ȘTERGE
toate cererile pot fi executate.
Ca majoritatea software-urilor open source, Retrofit a fost construit pe lângă alte biblioteci și instrumente puternice. În spatele scenei, Retrofit folosește OkHttp (de la același dezvoltator) pentru a gestiona cererile de rețea. De asemenea, Retrofit nu are un convertor JSON încorporat pentru a analiza obiectele JSON de la Java. În schimb, livrează suport pentru următoarele biblioteci de conversie JSON pentru a rezolva următoarele probleme:
com.squareup.retrofit: convertor-gson
com.squareup.retrofit: convertor-jackson
com.squareup.retrofit: convertor-Moshi
Pentru tampoanele de protocol, Retrofit suporta:
com.squareup.retrofit2: convertor-Protobuf
com.squareup.retrofit2: convertor fire
Și pentru XML, Retrofit sprijină:
com.squareup.retrofit2: convertor-simpleframework
Dezvoltarea propriei biblioteci HTTP de tip pentru a interfața cu un API REST poate fi o adevărată durere: trebuie să vă ocupați de multe funcționalități cum ar fi crearea conexiunilor, cache-ul, reîncercarea solicitărilor nereușite, filetarea, parsarea răspunsurilor, tratarea erorilor și multe altele. Retrofit, pe de altă parte, este foarte bine planificat, documentat și testat - o bibliotecă testată de luptă care vă va economisi mult timp prețios și dureri de cap.
În acest tutorial, vă voi explica cum să utilizați Retrofit 2 pentru a gestiona solicitările de rețea construind o aplicație simplă pentru a interoga răspunsurile recente din API-ul Stack Exchange. Vom efectua OBȚINE
solicitări prin specificarea unui obiectiv final-/ răspunsuri
, atașat la URL-ul de bază https://api.stackexchange.com/2.2/- apoi obțineți rezultatele și afișați-le într-un ecran de reciclare. De asemenea, vă voi arăta cum să faceți acest lucru cu RxJava pentru o gestionare ușoară a fluxului de stare și date.
Activați Android Studio și creați un nou proiect cu o activitate goală numită Activitate principala
.
După crearea unui nou proiect, declarați următoarele dependențe în dvs. build.gradle
. Dependențele includ o vizualizare a reciclării, biblioteca Retrofit și, de asemenea, biblioteca Google a lui Gson pentru a converti JSON în POJO (obiecte simple Java obișnuite), precum și integrarea Gson a Retrofit.
// Retrofit compile 'com.squareup.retrofit2: modernizare: 2.1.0' // JSON Parsing compile 'com.google.code.gson: gson: 2.6.1' compilați com.squareup.retrofit2: convertor-gson: 2.1 .0 '// reciclerview compile' com.android.support:recyclerview-v7:25.0.1 '
Nu uitați să sincronizați proiectul pentru a descărca aceste biblioteci.
Pentru a efectua operațiuni de rețea, trebuie să includeți INTERNET
permisiune în manifestarea cererii: AndroidManifest.xml.
Vom crea automat modelele noastre din datele noastre de răspuns JSON utilizând un instrument foarte util: jsonschema2pojo.
Copiați și lipiți https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow în bara de adrese a browserului dvs. (sau puteți utiliza Postman dacă sunteți familiarizat cu instrumentul respectiv). Apoi apăsați introduce-aceasta va executa o solicitare GET pentru obiectivul dat. Ce veți vedea în răspuns este o serie de obiecte JSON. Imaginea de mai jos este răspunsul JSON folosind Postman.
"items": ["proprietar": "reputație": 1, "user_id": 6540831, "user_type": "înregistrat", "profile_image": "https://www.gravatar.com/avatar/6a468ce8a8ff42c17923a6009ab77723 ? s = 128 & d = identiticon & r = PG & f = 1 "," display_name ":" bobolafrite "," link ":" http://stackoverflow.com/users/6540831/bobolafrite " : 0, "last_activity_date": 1480862271, "create_date": 1480862271, "answer_id": 40959732, "question_id": 35931342, "owner": reputation ": 629," user_id ": 3054722; "înregistrat", "profile_image": "https://www.gravatar.com/avatar/0cf65651ae9a3ba2858ef0d0a7dbf900?s=128&d=identicon&r=PG&f=1", "display_name": "jeremy-denis", "link": "http : //www.accountflow.com/indeers/3054722/jeremy-denis "," is_accepted ": false," score ": 0," last_activity_date ": 1480862260," creation_date ": 1480862260," answer_id " : 40959661, ...], "has_more": true, "backoff": 10, "quota_max": 300, "quota_remaining": 241
Copiați acest răspuns JSON fie din browserul dvs., fie din Postman.
Acum vizitați jsonschema2pojo și inserați răspunsul JSON în caseta de introducere.
Selectați un tip de sursă de JSON, stilul de adnotare al Gson, și debifați Permiteți proprietăți suplimentare.
Apoi faceți clic pe previzualizare pentru a genera obiectele Java.
S-ar putea să te întrebi ce @SerializedName
și @Expune
se fac adnotări în acest cod generat. Nu-ți face griji, o să explic totul!
@SerializedName
este nevoie de adnotări pentru ca Gson să găsească cheile JSON cu câmpurile noastre. În conformitate cu convenția Java de numire camelCase pentru proprietățile membrilor de clasă, nu se recomandă utilizarea sublinierii pentru separarea cuvintelor într-o variabilă. @SerializedName
ajută la traducerea între cele două.
@SerializedName ("quota_remaining") @ Expune cota intregului privatRemaining;
În exemplul de mai sus, îi spunem lui Gson cheia noastră JSON quota_remaining
ar trebui să fie mapate în câmpul Java quotaRemaining
. Dacă ambele valori au fost aceleași, adică dacă cheia noastră JSON a fost quotaRemaining
la fel ca domeniul Java, atunci nu ar fi nevoie de @SerializedName
adnotări pe teren deoarece Gson le-ar cartografia automat.
@Expune
adnotarea indică faptul că acest membru ar trebui expus pentru serializare sau deserializare JSON.
Acum, să revenim la Android Studio. Creați un nou sub-pachet în interiorul pachetului principal și denumiți-l date. În noul pachet de date creat, creați un alt pachet și denumiți-l model. În interiorul pachetului de modele, creați o nouă clasă Java și denumiți-o Proprietar
. Acum copiați Proprietar
clasa care a fost generată de jsonschema2pojo și inserați-o în interiorul Proprietar
clasa pe care ați creat-o.
importați com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; proprietarul clasei publice @SerializedName ("reputația") @ Expune reputația privată integrată; @SerializedName ("user_id") @Expose private UserId; @SerializedName ("user_type") @Expose privateType String; @SerializedName ("profile_image") @Exprimarea profilului privat StringImage; @SerializedName ("display_name") @Expongeți numele de afișare privat displayName; @SerializedName ("link") @ Expune link-ul privat String; @SerializedName ("accept_rate") @Export privat integer acceptRate; public Integer getReputation () retur reputație; public void setReputație (reputația întregului) this.reputation = reputație; Integer public getUserId () return userId; public void setUserId (Integer userId) this.userId = userId; public String getUserType () retur userType; public void setUserType (String userType) this.userType = userType; public String getProfileImage () returnare profilImage; void public setProfileImage (String profilImage) this.profileImage = ProfilImage; public String getDisplayName () retur displayName; void public setDisplayName (String displayName) this.displayName = displayName; public String getLink () return link; public void setLink (link-ul de șir) this.link = link; Integer public getAcceptRate () return acceptate; void public setAcceptRate (Integer acceptRate) this.acceptRate = acceptRate;
Faceți același lucru pentru un nou produs Articol
clasă, copiat de la jsonschema2pojo.
importați com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; element public de clasă @SerializatName ("proprietar") @ Expune proprietarul de proprietar privat; @SerializedName ("is_accepted") @Expose boolean privat esteAccepted; @SerializedName ("scorul") @Expune scorul privat Integer; @SerializedName ("last_activity_date") @Exploacă integer privat lastActivityDate; @SerializedName ("creation_date") @Expune crearea intregului privatDate; @SerializedName ("answer_id") @Export privat Integer answerId; @SerializedName ("question_id") @Expose private Identificator întrebare; @SerializedName ("last_edit_date") @Exploți întregul privat lastEditDate; public Proprietar getOwner () retur proprietar; public void setOwner (proprietar de proprietar) this.owner = proprietar; boolean public getIsAccepted () return este Accepted; public void setIsAccepted (boolean esteAccepted) this.isAccepted = esteAccepted; Integer public getScore () return score; public void setScore (scor întreg) this.score = scor; Integer public getLastActivityDate () return lastActivityDate; void public setLastActivityDate (Integer lastActivityDate) this.lastActivityDate = lastActivityDate; Integer public getCreationDate () return creationDate; public void setCreationDate (integer createDate) this.creationDate = creationDate; Integer public getAnswerId () return answerId; void public setAnswerId (Integer răspunsId) this.answerId = answerId; Integer public getQuestionId () returnIndicationId; public void setQuestionId (intrebare interogareId) this.questionId = questionId; Integer public getLastEditDate () return lastEditDate; void public setLastEditDate (Integer lastEditDate) this.lastEditDate = lastEditDate;
În cele din urmă, creați o clasă numităSOAnswersResponse
pentru răspunsurile StackOverflow returnate. Veți găsi codul pentru această clasă în jsonschema2pojo as Exemplu
. Asigurați-vă că actualizați numele clasei la SOAnswersResponse
oriunde se întâmplă.
importați com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import java.util.List; clasa publică SOAnswersResponse @SerializedName ("items") @ Expune lista privată- elemente = null; @SerializedName ("has_more") @Expose boolean privat hasMore; @SerializedName ("backoff") @Exponați privat Integer backoff; @SerializedName ("quota_max") @Exploți cota privată privatăMax; @SerializedName ("quota_remaining") @ Expune cota intregului privatRemaining; Lista publică
- getItems () return items; public void setItems (Listă
- elemente) this.items = items; boolean public getHasMore () return hasMore; public void setHasMore (Boolean are mai mult) this.hasMore = hasMore; Integer public getBackoff () return backoff; void publice setBackoff (Integer backoff) this.backoff = backoff; Integer public getQuotaMax () return quotaMax; void public setQuotaMax (cota întreguluiMax) this.quotaMax = quotaMax; Integer public getQuotaRemaining () return cotaRemaining; public void setQuotaRemaining (cota intreguluiRemaining) this.quotaRemaining = cotaRemaining;
Pentru a emite cereri de rețea către un API REST cu Retrofit, trebuie să creați o instanță folosind Retrofit.Builder
clasați și configurați-o cu o adresă URL de bază.
Creați un nou pachet sub-pachet în interiorul date
pachet și numele acestuia la distanta
. Acum înăuntru la distanta
, creați o clasă Java și denumiți-o RetrofitClient
. Această clasă va crea un singleton de Retrofit. Retrofit-ul are nevoie de o adresă URL de bază pentru a-și construi instanța, așa că vom transmite un URL atunci când sunăm RetrofitClient.getClient (String baseUrl)
. Această adresă URL va fi apoi utilizată pentru a construi instanța în rândul 13. De asemenea, specificăm convertorul JSON de care avem nevoie (Gson) în rândul 14.
import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; clasa publică RetrofitClient private static Retrofit retrofit = null; public static Retrofit getClient (String baseUrl) if (retrofit == null) retrofit = nou Retrofit.Builder () .baseUrl (baseUrl) .addConverterFactory (GsonConverterFactory.create ()) .build (); retrofit retur;
În interiorul pachetului de la distanță, creați o interfață și apelați-o SOService
. Această interfață conține metode pe care le vom folosi pentru a executa cereri HTTP, cum ar fi OBȚINE
, POST
, A PUNE
, PLASTURE
, și ȘTERGE
. Pentru acest tutorial, vom executa a OBȚINE
cerere.
import com.chikeandroid.retrofittutorial.data.model.SOAnswersResponse; import java.util.List; import retrofit2.Call; import retrofit2.http.GET; interfața publică SOService @GET ("/ answers? order = desc & sort = activity & site = stackoverflow")(); obțineți răspunsuri @GET ("/ answers? Order = desc & sort = activity & site = stackoverflow") Apel getAnswers (@Query ("tagged") Etichete de coarde);
@OBȚINE
adnotarea specifică în mod explicit acest lucru OBȚINE
cererea care va fi executată odată ce metoda va fi apelată. Fiecare metodă din această interfață trebuie să aibă o adnotare HTTP care oferă metoda de solicitare și adresa URL relativă. Există cinci adnotări încorporate disponibile: @OBȚINE
, @POST
, @A PUNE
, @ȘTERGE
, și @CAP
.
În a doua definiție a metodei, am adăugat un parametru de interogare pentru a filtra datele de pe server. Retrofit are funcția @Query ( "cheie")
adnotare de utilizat în loc de codificare greu în punctul final. Valoarea cheie reprezintă numele parametrului din adresa URL. Acesta va fi adăugat la adresa URL de către Retrofit. De exemplu, dacă depășim valoarea "Android"
ca argument pentru getAnswers (etichete cu coarde)
, adresa URL completă va fi:
https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow&tagged=android
Parametrii metodelor de interfață pot avea următoarele adnotări:
@Cale | substituție variabilă pentru obiectivul API |
@Query | specifică numele cheii de interogare cu valoarea parametrului adnotat |
@Corp | sarcină utilă pentru apelul POST |
@Antet | specifică antetul cu valoarea parametrului adnotat |
Acum se va crea o clasă de utilități. O vom numi ApiUtils
. Această clasă va avea adresa URL de bază ca variabilă statică și va furniza și SOService
interfață cu aplicația noastră prin intermediul getSOService ()
metoda statică.
clasa publică ApiUtils String public static final BASE_URL = "https://api.stackexchange.com/2.2/"; serviciul public static SOService getSOService () întoarcere RetrofitClient.getClient (BASE_URL) .create (SOService.class);
Deoarece rezultatele vor fi afișate într-o vizualizare de reciclare, avem nevoie de un adaptor. Următorul fragment de cod afișează AnswersAdapter
clasă.
clasa publică AnswersAdapter extinde RecyclerView.Adapterlistă privată - mItems; Context privat mContext; private PostItemListener mItemListener; clasa publică ViewHolder extinde RecyclerView.ViewHolder implementează View.OnClickListener public TextView titleTv; PostItemListener mItemListener; public ViewHolder (Vizualizare itemView, PostItemListener postItemListener) super (itemView); titluTv = (TextView) itemView.findViewById (android.R.id.text1); this.mItemListener = postItemListener; itemView.setOnClickListener (aceasta); @Override public void onClick (Vizualizare vizualizare) Item item = getItem (getAdapterPosition ()); this.mItemListener.onPostClick (item.getAnswerId ()); notifyDataSetChanged (); public AnswersAdapter (context context, lista
- posturi, PostItemListener itemListener) mItems = posturi; mContext = context; mItemListener = itemListener; @Override publice AnswersAdapter.ViewHolder onCreateViewHolder (parentă ViewGroup, int viewType) Context context = parent.getContext (); LayoutInflater inflater = LayoutInflater.from (context); Afișați postView = inflater.inflate (android.R.layout.simple_list_item_1, parent, false); ViewHolder viewHolder = ViewHolder nou (postView, this.mItemListener); retur ViewHolder; @Overide public void onBindViewHolder (Titluri răspunsuriAdapter.ViewHolder, poziție int) Item item = mItems.get (position); TextView textView = titular.titleTv; textView.setText (item.getOwner () getDisplayName ().); @Override public int getItemCount () retur mItems.size (); public void updateAnswers (Listă
- elemente) mItems = elemente; notifyDataSetChanged (); element privat getItem (int adapterPosition) return mItems.get (adapterPosition); interfață publică PostItemListener void onPostClick (id lung);
În interiorul onCreate ()
metodă a Activitate principala
, inițializăm o instanță a SOService
interfața (linia 9), vizualizarea reciclării și, de asemenea, adaptorul. În cele din urmă, numim loadAnswers ()
metodă.
private AnswersAdapter mAdapter; privat RecyclerView mRecyclerView; privat SOService mService; @Override protejate 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 (acest nou ArrayList- (0), noul AnswersAdapter.PostItemListener () @Override public void onPostClick (id lung) Toast.makeText (MainActivity.this, "ID-ul postului este" + id, Toast.LENGTH_SHORT) .show (); ); RecyclerView.LayoutManager layoutManager = nou LinearLayoutManager (acest lucru); mRecyclerView.setLayoutManager (layoutManager); mRecyclerView.setAdapter (mAdapter); mRecyclerView.setHasFixedSize (true); RecyclerView.ItemDecoration itemDecoration = noua DividerItemDecoration (aceasta, DividerItemDecoration.VERTICAL_LIST); mRecyclerView.addItemDecoration (itemDecoration); loadAnswers ();
loadAnswers ()
metoda face o solicitare de rețea prin apelare Puneți în coadă ()
. Când răspunsul se întoarce, Retrofit ne ajută să analizăm răspunsul JSON la o listă de obiecte Java. (Acest lucru este posibil prin utilizarea GsonConverter
.)
public void loadAnswers () mService.getAnswers (). enqueue (nou apel invers() @Override public void onResponse (Apel apel, răspuns răspuns) if (answer.isSuccessful ()) mAdapter.updateAnswers (răspuns.body (). getItems ()); Log.d ("MainActivity", "posturi încărcate de la API"); altceva int statusCode = answer.code (); // preluați erorile de solicitare în funcție de codul de stare @Override public void onFailure (Apel apel, Throwable t) showErrorMessage (); Log.d ("MainActivity", "eroare de încărcare din API"); );
Puneți în coadă ()
Puneți în coadă ()
asynchronously trimite cererea și notifică aplicația dvs. cu un apel invers atunci când un răspuns vine înapoi. Deoarece această solicitare este asincronă, Retrofit se ocupă de un fir de fundal astfel încât firul principal al UI să nu fie blocat sau interferat cu.
A folosi Puneți în coadă ()
, trebuie să implementați două metode de apel invers:
onResponse ()
onFailure ()
Numai una dintre aceste metode va fi apelată ca răspuns la o cerere dată.
onResponse ()
: invocat pentru un răspuns HTTP primit. Această metodă este solicitată pentru un răspuns care poate fi gestionat corect, chiar dacă serverul returnează un mesaj de eroare. Deci, dacă primiți un cod de stare de 404 sau 500, această metodă va fi în continuare apelată. Pentru a obține codul de stare pentru a putea face față situațiilor bazate pe acestea, puteți folosi metoda response.code ()
. De asemenea, puteți utiliza funcția este de succes()
pentru a afla dacă codul de stare este în intervalul 200-300, indicând succesul.onFailure ()
: invocată atunci când a apărut o excepție de rețea care a comunicat serverului sau când a apărut o excepție neașteptată care gestiona solicitarea sau procesarea răspunsului. Pentru a efectua o cerere sincronă, puteți utiliza funcția a executa()
metodă. Rețineți că metodele sincrone pe firul principal / interfața de utilizare vor bloca orice acțiune a utilizatorului. Deci, nu executați metode sincrone pe firul principal al Android / UI! În schimb, rulați-le pe un fir de fundal.
Acum puteți rula aplicația.
Dacă sunteți un fan al RxJava, puteți implementa cu ușurință Retrofit cu RxJava. În Retrofit 1 a fost integrat în mod implicit, dar în Retrofit 2 trebuie să includeți unele dependențe suplimentare. Retrofitează navele cu un adaptor implicit pentru execuție Apel
instanțe. Deci, puteți schimba mecanismul de execuție al Retrofit pentru a include RxJava prin includerea RxJava CallAdapter
.
Adăugați dependențele.
compilați 'io.reactivex: rxjava: 1.1.6' compilați 'io.reactivex: rxandroid: 1.2.1' compile 'com.squareup.retrofit2: adapter-rxjava: 2.1.0'
Adăugați noul CallAdapter RxJavaCallAdapterFactory.create ()
când construiți o instanță Retrofit.
public static Retrofit getClient (String baseUrl) if (retrofit == null) retrofit = nou Retrofit.Builder () .baseUrl (baseUrl) .addCallAdapterFactory (RxJavaCallAdapterFactory.create ()) .addConverterFactory (GsonConverterFactory.create (); retrofit retur;
Actualizați acum () obțineți răspunsuri
metode de returnare Observabil
s:
@GET ("/ answer? Order = desc & sort = activity & site = stackoverflow") Observabil(); obțineți răspunsuri @GET ("/ answer? Order = desc & sort = activity & site = stackoverflow") Observabil getAnswers (@Query ("tagged") Etichete de coarde);
Când facem cererile, abonatul nostru anonim răspunde la fluxul observabil care emite evenimente, în cazul nostru SOAnswersResponse
. onNext
este apelată atunci când abonatul nostru primește orice eveniment emis, care este apoi trecut la adaptorul nostru.
@Override public void loadAnswers () mService.getAnswers (). SubscribeOn (Schedulers.io ()) observeOn (AndroidSchedulers.mainThread ()) .subscribe (noul abonat() @Override public void onCompleted () @Override public void peError (Throwable e) @Override publice void onNext (SOAnswersResponse soAnswersResponse) mAdapter.updateAnswers (soAnswersResponse.getItems ()); );
Verificați începutul cu ReactiveX pe Android de Ashraff Hathibelagal pentru a afla mai multe despre RxJava și RxAndroid.
În acest tutorial, ați aflat despre Retrofit: de ce ar trebui să o utilizați și cum. De asemenea, am explicat cum să adăugați integrarea RxJava cu Retrofit. În următoarea mea postare, vă voi arăta cum să efectuați POST
, A PUNE
, și ȘTERGE
, cum să trimită Formular-urlencoded
datele și modul de anulare a cererilor.
Pentru a afla mai multe despre Retrofit, consultați documentația oficială. Între timp, verificați câteva dintre celelalte cursuri și tutoriale ale dezvoltării aplicațiilor Android.