Retrofit er en type sikker HTTP-klient for Android og Java. Retrofit gjør det enkelt å koble til en REST webtjeneste ved å oversette API-en til Java-grensesnitt. I denne veiledningen viser jeg deg hvordan du bruker en av de mest populære og ofte anbefalte HTTP-bibliotekene som er tilgjengelige for Android.
Dette kraftige biblioteket gjør det enkelt å konsumere JSON- eller XML-data som deretter blir analysert i Vanlige gamle Java-objekter (POJOs). FÅ
, POST
, SETTE
, LAPP
, og SLETT
forespørsler kan alle bli utført.
Som de fleste open source-programvare ble Retrofit bygget på toppen av noen andre kraftige biblioteker og verktøy. Bak kulissene bruker Retrofit OkHttp (fra samme utvikler) til å håndtere nettverksforespørsler. Også, Retrofit har ikke en innebygd hvilken som helst JSON-omformer for å analysere fra JSON til Java-objekter. I stedet sender den støtte til følgende JSON-konverteringsbiblioteker for å håndtere det:
com.squareup.retrofit: converter-gson
com.squareup.retrofit: converter-jackson
com.squareup.retrofit: converter-moshi
For protokollbuffere støtter Retrofit:
com.squareup.retrofit2: converter-Protobuf
com.squareup.retrofit2: konverter-ledning
Og for XML støtter Retrofit:
com.squareup.retrofit2: converter-simpleframework
Å utvikle ditt eget type-sikre HTTP-bibliotek til grensesnitt med en REST-API kan være en reell smerte: du må håndtere mange funksjoner, for eksempel å lage tilkoblinger, cache, forsøke mislykkede forespørsler, tråder, responsanalyse, feilsøking og mer. Retrofit, derimot, er meget godt planlagt, dokumentert og testet - et kamptestet bibliotek som vil spare deg for mye dyrebar tid og hodepine.
I denne veiledningen vil jeg forklare hvordan du bruker Retrofit 2 til å håndtere nettverksforespørsler ved å bygge en enkel app for å søke etter de siste svarene fra Stack Exchange API. Vi skal utføre FÅ
forespørsler ved å spesifisere et sluttpunkt-/ svar
, vedlagt til basen URL https://api.stackexchange.com/2.2/-then få resultatene og vise dem i en resirkuleringsvisning. Jeg vil også vise deg hvordan du gjør dette med RxJava for enkel styring av strømmen av tilstand og data.
Brann opp Android Studio og opprett et nytt prosjekt med en tom aktivitet som heter Hoved aktivitet
.
Når du har opprettet et nytt prosjekt, erklærer du følgende avhengigheter i din build.gradle
. Avhengighetene inkluderer en resirkuleringsvisning, Retrofit-biblioteket, og også Googles Gson-bibliotek for å konvertere JSON til POJO (Plain Old Java Objects) samt Retrofits Gson-integrasjon.
// Retrofit compile 'com.squareup.retrofit2: retrofit: 2.1.0' // JSON Parsing compile 'com.google.code.gson: gson: 2.6.1' compile 'com.squareup.retrofit2: converter-gson: 2.1 .0 '// recyclerview compile' com.android.support:recyclerview-v7:25.0.1 '
Ikke glem å synkronisere prosjektet for å laste ned disse bibliotekene.
For å utføre nettverksoperasjoner må vi inkludere INTERNETT
Tillatelse i søknadsmanifestet: AndroidManifest.xml.
Vi skal lage våre modeller automatisk fra våre JSON-responsdata ved å utnytte et veldig nyttig verktøy: jsonschema2pojo.
Kopier og lim inn https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow i nettleserens adresselinje (eller du kan bruke Postman hvis du er kjent med verktøyet). Trykk deretter på Tast inn-Dette vil utføre en GET-forespørsel på det angitte sluttpunktet. Det du vil se som svar er en rekke JSON-objekter. Skjermbildet nedenfor er JSON-responsen ved hjelp av Postman.
"elementer": ["eier": "omdømme": 1, "user_id": 6540831, "user_type": "registrert", "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 " : 0, "last_aktivitet_date": 1480862271, "creation_date": 1480862271, "answer_id": 40959732, "question_id": 35931342, "eier": "omdømme": 629, "user_id": 3054722, "user_type": "registrert", "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_aktivitet_date ": 1480862260," creation_date ": 1480862260," answer_id ": 40959731," question_id " : 40959661, ...], "has_more": true, "backoff": 10, "quota_max": 300, "quota_remaining": 241
Kopier denne JSON-responsen enten fra nettleseren din eller fra Postman.
Nå besøker jsonschema2pojo og lim inn JSON-responsen i innskuffen.
Velg en kilde type av JSON, annoteringsstil av Gson, og fjern markeringen Tillat flere egenskaper.
Klikk deretter på Forhåndsvisning knappen for å generere Java-objektene.
Du lurer kanskje på hva @SerializedName
og @Avdekke
merknader gjør i denne genererte koden. Ikke bekymre deg, jeg forklarer alt!
De @SerializedName
Merknad er nødvendig for Gson å kartlegge JSON-nøklene med feltene våre. I tråd med Java's kamelCase-navngivningskonvensjon for klassemedlemsegenskaper, anbefales det ikke å bruke understreker til å skille ord i en variabel. @SerializedName
hjelper å oversette mellom de to.
@SerializedName ("quota_remaining") @Visstilt privat integer kvoteRemaining;
I eksemplet ovenfor forteller vi Gson at vår JSON-nøkkel quota_remaining
bør kartlegges til Java-feltet quotaRemaining
. Hvis begge disse verdiene var de samme, dvs. hvis vår JSON-nøkkel var quotaRemaining
akkurat som Java-feltet, så ville det ikke være behov for @SerializedName
annotasjon på feltet fordi Gson ville kartlegge dem automatisk.
De @Avdekke
annotasjon indikerer at dette medlemmet skal bli utsatt for JSON serialisering eller deserialisering.
La oss nå gå tilbake til Android Studio. Opprett en ny delpakke i hovedpakken og merk den data. I den nyopprettede datapakken skal du opprette en annen pakke og gi den navnet modell. Inne i modellpakken, opprett en ny Java-klasse og gi den navnet Eieren
. Kopier nå Eieren
klassen som ble generert av jsonschema2pojo og lim den inn i Eieren
klasse du opprettet.
importer com.google.gson.annotations.Expose; importer com.google.gson.annotations.SerializedName; offentlig klasse Eier @SerializedName ("omdømme") @Visstilt privat integer omdømme; @SerializedName ("user_id") @Viser privat integer brukerId; @SerializedName ("user_type") @Uppdater privat String userType; @SerializedName ("profile_image") @Visstille private strengprofilImage; @SerializedName ("display_name") @Visstille privat string displayName; @SerializedName ("link") @Uppfyll privat strengekobling; @SerializedName ("accept_rate") @Viser privat integer acceptereRate; offentlig integer getReputation () return reputation; offentlig ugyldig setReputation (integer rykte) this.reputation = reputation; offentlig integer getUserId () return userId; Offentlig tomgang setUserId (Integer userId) this.userId = userId; offentlig String getUserType () return userType; offentlig tomgang setUserType (String userType) this.userType = userType; Offentlig String getProfileImage () return profileImage; Offentlig tomgangssettProfileImage (StringprofilImage) this.profileImage = profileImage; Offentlig String getDisplayName () return displayName; offentlig ugyldig setDisplayName (String displayName) this.displayName = displayName; offentlig String getLink () returlink; Offentlig tomt settLink (Stringlink) this.link = link; offentlig integer getAcceptRate () return acceptRate; offentlig tomgang setAcceptRate (Integer acceptRate) this.acceptRate = acceptRate;
Gjør det samme for en ny Punkt
klassen, kopiert fra jsonschema2pojo.
importer com.google.gson.annotations.Expose; importer com.google.gson.annotations.SerializedName; offentlig klasse Element @SerializedName ("eier") @Verlegg privat eier eier; @SerializedName ("is_accepted") @Expose Private Boolean isAccepted; @SerializedName ("score") @Uppfyll privat integerpoengsum; @SerializedName ("last_activity_date") @Verlegg privat integer lastAktivitetDate; @SerializedName ("creation_date") @Visstilt privat integer creationDate; @SerializedName ("answer_id") @Visstilt privat integer svar; @SerializedName ("question_id") @Visstilt privat integer spørsmålId; @SerializedName ("last_edit_date") @Viser privat integer lastEditDate; offentlig eier getOwner () retur eier; Offentlig tomt settOwner (Eier eier) this.owner = owner; offentlige boolske getIsAccepted () return isAccepted; Offentlig tomgang setIsAccepted (Boolean isAccepted) this.isAccepted = isAccepted; offentlig Integer getScore () return score; Offentlig tomt settScore (Integer score) this.score = score; offentlig integer getLastActivityDate () return lastActivityDate; offentlig tomt settLastActivityDate (Integer lastActivityDate) this.lastActivityDate = lastActivityDate; offentlig integer getCreationDate () return creationDate; offentlig tomt settCreationDate (Integer creationDate) this.creationDate = creationDate; offentlig integer getAnswerId () return answerId; Offentlig tomt settAnswerId (Integer svar) this.answerId = answerId; offentlig integer getQuestionId () return questionId; offentlig tomt settQuestionId (Integer questionId) this.questionId = questionId; offentlig integer getLastEditDate () return lastEditDate; offentlig tomgang setLastEditDate (Integer lastEditDate) this.lastEditDate = lastEditDate;
Endelig opprett en klasse som heterSOAnswersResponse
for de returnerte StackOverflow svarene. Du finner koden for denne klassen i jsonschema2pojo as Eksempel
. Pass på at du oppdaterer klassenavnet til SOAnswersResponse
uansett hvor det skjer.
importer com.google.gson.annotations.Expose; importer com.google.gson.annotations.SerializedName; importer java.util.List; offentlig klasse SOAnswersResponse @SerializedName ("items") @Verlegg privat liste- elementer = null; @SerializedName ("has_more") @Bygg privat boolsk harMore; @SerializedName ("backoff") @Uppgå privat integerbackoff; @SerializedName ("quota_max") @Viser privat integer kvoteMax; @SerializedName ("quota_remaining") @Visstilt privat integer kvoteRemaining; offentlig liste
- getItems () returelementer; offentlig tomt setItems (Liste
- elementer) this.items = items; offentlig boolsk getHasMore () return harMore; offentlig tomgang setHasMore (Boolean harMore) this.hasMore = hasMore; offentlig integer getBackoff () return backoff; Offentlig tomt settBackoff (Integer backoff) this.backoff = backoff; offentlig Integer getQuotaMax () return quotaMax; offentlig tomgang setQuotaMax (Integer quotaMax) this.quotaMax = quotaMax; offentlig integer getQuotaRemaining () return kvoteRemaining; Offentlig ugyldig setQuotaRemaining (Integer quotaRemaining) this.quotaRemaining = quotaRemaining;
Hvis du vil utstede nettverksforespørsler til en REST-API med Retrofit, må vi opprette en forekomst ved hjelp av Retrofit.Builder
klasse og konfigurere den med en base URL.
Lag en ny delpakkepakke inne i data
pakke og navn den fjern
. Nå inne fjern
, opprett en Java-klasse og gi den navnet RetrofitClient
. Denne klassen vil skape en singleton av Retrofit. Retrofit trenger en basiswebadresse for å bygge sin forekomst, så vi sender en nettadresse når du ringer RetrofitClient.getClient (String baseUrl)
. Denne URL-en vil da bli brukt til å bygge forekomsten i linje 13. Vi spesifiserer også den JSON-omformer vi trenger (Gson) på linje 14.
importere retrofit2.Retrofit; importere retrofit2.converter.gson.GsonConverterFactory; offentlig klasse RetrofitClient privat statisk Retrofit retrofit = null; offentlig statisk Retrofit getClient (String baseUrl) if (retrofit == null) retrofit = ny Retrofit.Builder () .baseUrl (baseUrl) .addConverterFactory (GsonConverterFactory.create ()) .build (); returnere ettermontering
Inne i den eksterne pakken, opprett et grensesnitt og ring det SOService
. Dette grensesnittet inneholder metoder vi skal bruke til å utføre HTTP-forespørsler som FÅ
, POST
, SETTE
, LAPP
, og SLETT
. For denne opplæringen skal vi utføre en FÅ
be om.
importer com.chikeandroid.retrofittutorial.data.model.SOAnswersResponse; importer java.util.List; importere retrofit2.Call; importere retrofit2.http.GET; offentlig grensesnitt SOService @GET ("/ answers? order = desc & sort = aktivitet & site = stackoverflow") Ringfåsvar (); @GET ("/ answers? Order = desc & sort = aktivitet & site = stackoverflow") Ring getAnswers (@Query ("tagged") String tags);
De @FÅ
annotasjon definerer eksplisitt det FÅ
forespørsel som vil bli utført når metoden blir kalt. Hver metode i dette grensesnittet må ha en HTTP-annotasjon som gir forespørselsmetoden og relativ nettadresse. Det finnes fem innebygde merknader: @FÅ
, @POST
, @SETTE
, @DELETE
, og @HODE
.
I den andre metoden definisjonen la vi til en spørringsparameter for å filtrere dataene fra serveren. Retrofit har @Query ( "nøkkel")
annotasjon til bruk i stedet for hardkoding i sluttpunktet. Nøkkelverdien representerer parameternavnet i nettadressen. Det vil bli lagt til URL-adressen av Retrofit. For eksempel, hvis vi overfører verdien "Android"
som et argument til getAnswers (String tags)
Metoden, den fulle nettadressen vil være:
https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow&tagged=android
Parametre for grensesnittmetodene kan ha følgende merknader:
@Sti | variabel substitusjon for API-endepunktet |
@Spørsmål | Angir forespørselsnøkkelnavnet med verdien av den annoterte parameteren |
@Kropp | nyttelast for POST-anropet |
@Overskrift | Angir toppteksten med verdien av den merkede parameteren |
Nå skal du lage en verktøysklasse. Vi nevner det ApiUtils
. Denne klassen vil ha basen URL som en statisk variabel og også gi SOService
grensesnitt til vår søknad gjennom getSOService ()
statisk metode.
offentlig klasse ApiUtils offentlig statisk endelig streng BASE_URL = "https://api.stackexchange.com/2.2/"; offentlig statisk SOService getSOService () returner RetrofitClient.getClient (BASE_URL) .create (SOService.class);
Siden resultatene vil bli vist i en resirkuleringsvisning, trenger vi en adapter. Følgende kodestykke viser AnswersAdapter
klasse.
offentlig klasse AnswersAdapter utvider RecyclerView.Adapterprivat liste - mItems; privat kontekst mContext; privat PostItemListener mItemListener; offentlig klasse ViewHolder utvider RecyclerView.ViewHolder implementerer View.OnClickListener public TextView titleTv; PostItemListener mItemListener; offentlig ViewHolder (Se itemView, PostItemListener postItemListener) super (itemView); titleTv = (TextView) itemView.findViewById (android.R.id.text1); this.mItemListener = postItemListener; itemView.setOnClickListener (this); @Override public void onClick (View view) Item item = getItem (getAdapterPosition ()); this.mItemListener.onPostClick (item.getAnswerId ()); notifyDataSetChanged (); offentlig svaradapter (kontekst kontekst, liste
- innlegg, PostItemListener itemListener) mItems = innlegg; mContext = kontekst; mItemListener = itemListener; @Override public AnswersAdapter.ViewHolder onCreateViewHolder (ViewGroup foreldre, int viewType) Context context = parent.getContext (); LayoutInflater inflater = LayoutInflater.from (kontekst); Se postView = inflater.inflate (android.R.layout.simple_list_item_1, foreldre, falsk); ViewHolder viewHolder = ny ViewHolder (postView, this.mItemListener); returnere viewHolder; @Override public void onBindViewHolder (AnswersAdapter.ViewHolder holder, int posisjon) Item item = mItems.get (posisjon); TextView textView = holder.titleTv; textView.setText (item.getOwner () getDisplayName ().); @ Overstyr offentlig int getItemCount () return mItems.size (); offentlig ugyldig oppdateringAnswers (Liste
- elementer) mItems = items; notifyDataSetChanged (); private Item getItem (int adapterPosition) return mItems.get (adapterposisjon); offentlig grensesnitt PostItemListener void onPostClick (long id);
Inne i onCreate ()
metode av Hoved aktivitet
, vi initialiserer en forekomst av SOService
grensesnitt (linje 9), resirkuleringsvisning, og også adapteren. Til slutt kaller vi loadAnswers ()
metode.
private svarAdapter mAdapter; privat RecyclerView mRecyclerView; privat SOService mService; @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 = ny svarAdapter (denne nye ArrayList- (0), nye svarAdapter.PostItemListener () @Overtrid offentlig tomgang onPostClick (lang id) Toast.makeText (MainActivity.this, "Post id er" + id, Toast.LENGTH_SHORT) .show (); ); RecyclerView.LayoutManager layoutManager = ny LinearLayoutManager (denne); mRecyclerView.setLayoutManager (layoutManager); mRecyclerView.setAdapter (mAdapter); mRecyclerView.setHasFixedSize (true); RecyclerView.ItemDecoration itemDecoration = ny DividerItemDecoration (dette DividerItemDecoration.VERTICAL_LIST); mRecyclerView.addItemDecoration (itemDecoration); loadAnswers ();
De loadAnswers ()
Metode gjør en nettverksforespørsel ved å ringe Enqueue ()
. Når svaret kommer tilbake, hjelper Retrofit oss til å analysere JSON-responsen på en liste over Java-objekter. (Dette er gjort mulig ved å bruke GsonConverter
.)
offentlig ugyldig belastningAnswers () mService.getAnswers (). enqueue (ny tilbakeringing() @Overgå offentlig ugyldig påmelding (Ring ring, svar svar) if (response.isSuccessful ()) mAdapter.updateAnswers (response.body (). getItems ()); Log.d ("MainActivity", "Innlegg lastet fra API"); ellers int statusCode = response.code (); // Behandle forespørselsfeil avhengig av statuskode @Overvrid offentlig tomgang på feil (Ring ring, kastbar t) showErrorMessage (); Log.d ("MainActivity", "error loading from API"); );
Enqueue ()
Enqueue ()
Asynkront sender forespørselen og gir beskjed om appen din med tilbakeringing når et svar kommer tilbake. Siden denne forespørselen er asynkron, håndterer Retrofit den på en bakgrunnstråd, slik at hovedbruddstråden ikke er blokkert eller forstyrret med.
Å bruke Enqueue ()
, du må implementere to tilbakeringingsmetoder:
onResponse ()
onFailure ()
Bare en av disse metodene vil bli kalt som svar på en gitt forespørsel.
onResponse ()
: Påkrevd for mottatt HTTP-respons. Denne metoden kalles for et svar som kan håndteres på riktig måte, selv om serveren returnerer en feilmelding. Så hvis du får en statuskode på 404 eller 500, vil denne metoden fortsatt bli kalt. For å få statuskoden slik at du kan håndtere situasjoner basert på dem, kan du bruke metoden response.code ()
. Du kan også bruke isSuccessful ()
metode for å finne ut om statuskoden er i området 200-300, som indikerer suksess.onFailure ()
: Påkrevd når et nettverks unntak skjedde kommunikasjon til serveren eller når et uventet unntak oppstod, håndterer forespørselen eller behandler svaret. For å utføre en synkron forespørsel, kan du bruke henrette()
metode. Vær oppmerksom på at synkroniserte metoder på hoved / UI-tråden vil blokkere alle brukerhandlinger. Så ikke utfør synkroniserte metoder på Android hoved- / brukergrensesnitt! Kjør dem i stedet på en bakgrunnstråd.
Du kan nå kjøre appen.
Hvis du er fan av RxJava, kan du enkelt implementere Retrofit med RxJava. I Retrofit 1 ble det integrert som standard, men i Retrofit 2 må du ta med noen ekstra avhengigheter. Retrofit skip med en standardadapter for utførelse Anrop
forekomster. Så du kan endre Retrofits utførelsesmekanisme for å inkludere RxJava ved å inkludere RxJava CallAdapter
.
Legg til avhengighetene.
kompilere 'io.reactivex: rxjava: 1.1.6' compile 'io.reactivex: rxandroid: 1.2.1' compile 'com.squareup.retrofit2: adapter-rxjava: 2.1.0'
Legg til den nye CallAdapter RxJavaCallAdapterFactory.create ()
når du bygger en Retrofit-forekomst.
offentlig statisk Retrofit getClient (String baseUrl) if (retrofit == null) retrofit = ny Retrofit.Builder () .baseUrl (baseUrl) .addCallAdapterFactory (RxJavaCallAdapterFactory.create ()) .addConverterFactory (GsonConverterFactory.create ()) .build (); returnere ettermontering
Oppdater nå fåsvar ()
metoder for å returnere observer
s:
@GET ("/ answers? Order = desc & sort = activity & site = stackoverflow") Observerbarfåsvar (); @GET ("/ answers? Order = desc & sort = activity & site = stackoverflow") Observerbar getAnswers (@Query ("tagged") String tags);
Når du gjør forespørsler, svarer vår anonyme abonnent på den observerbare strømmen som avgir hendelser, i vårt tilfelle SOAnswersResponse
. De onNext
Metoden kalles da når abonnenten mottar noe som sendes ut, som sendes til vår adapter.
@Override public void loadAnswers () mService.getAnswers (). SubscribeOn (Schedulers.io ()). ObserveOn (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 ()); );
Sjekk ut Komme i gang med ReactiveX på Android av Ashraff Hathibelagal for å lære mer om RxJava og RxAndroid.
I denne opplæringen lærte du om Retrofit: hvorfor bør du bruke den og hvordan. Jeg forklarte også hvordan å legge til RxJava integrasjon med Retrofit. I mitt neste innlegg vil jeg vise deg hvordan du skal utføre POST
, SETTE
, og SLETT
, hvordan sende Form urlencoded
data, og hvordan du kansellerer forespørsler.
Hvis du vil vite mer om Retrofit, kan du se den offisielle dokumentasjonen. Og i mellomtiden, sjekk ut noen av våre andre kurs og opplæringsprogrammer på Android app utvikling.