1. Code
  2. Coding Fundamentals
  3. Rest API

Erste Schritte mit Retrofit 2 HTTP-Client

Retrofit ist ein typsicherer HTTP-Client für Android und Java. Retrofit macht es einfach, sich mit einem REST-Webservice zu verbinden, indem die API in Java-Schnittstellen übersetzt wird. In diesem Tutorial zeige ich Ihnen, wie Sie eine der beliebtesten und am häufigsten empfohlenen HTTP-Bibliotheken für Android verwenden.
Scroll to top

German (Deutsch) translation by Federicco Ancie (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Was ist Nachrüstung?

Retrofit ist ein typsicherer HTTP-Client für Android und Java. Retrofit macht es einfach, sich mit einem REST-Webservice zu verbinden, indem die API in Java-Schnittstellen übersetzt wird. In diesem Tutorial zeige ich Ihnen, wie Sie eine der beliebtesten und am häufigsten empfohlenen HTTP-Bibliotheken für Android verwenden.

Diese leistungsstarke Bibliothek macht es einfach, JSON- oder XML-Daten zu konsumieren, die dann in Plain Old Java Objects (POJOs) geparst werden. GET-, POST-, PUT-, PATCH- und DELETE-Anforderungen können alle ausgeführt werden.

Wie die meisten Open-Source-Software wurde Retrofit auf einigen anderen leistungsstarken Bibliotheken und Tools aufgebaut. Hinter den Kulissen verwendet Retrofit OkHttp (vom gleichen Entwickler), um Netzwerkanfragen zu bearbeiten. Außerdem verfügt Retrofit über keinen integrierten JSON-Konverter zum Parsen von JSON- in Java-Objekte. Stattdessen wird die Unterstützung für die folgenden JSON-Konverterbibliotheken bereitgestellt, um dies zu handhaben:

  • Gson: com.squareup.retrofit:converter-gson
  • Jackson: com.squareup.retrofit:converter-jackson
  • Moshi: com.squareup.retrofit:converter-moshi
  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire

Und für XML unterstützt Retrofit:

  • Einfaches Framework: com.squareup.retrofit2:converter-simpleframework

Warum also Retrofit verwenden?

Die Entwicklung einer eigenen typsicheren HTTP-Bibliothek für die Schnittstelle zu einer REST-API kann eine echte Herausforderung sein: Sie müssen viele Funktionen wie Herstellen von Verbindungen, Caching, Wiederholen fehlgeschlagener Anforderungen, Threading, Antwortparsing, Fehlerbehandlung und mehr bewältigen. Retrofit hingegen ist sehr gut geplant, dokumentiert und getestet – eine kampferprobte Bibliothek, die Ihnen viel kostbare Zeit und Kopfschmerzen erspart.

In diesem Tutorial erkläre ich, wie man Retrofit 2 verwendet, um Netzwerkanfragen zu bearbeiten, indem ich eine einfache App erstelle, um aktuelle Antworten von der Stack Exchange API abzufragen. Wir führen GET-Anfragen durch, indem wir einen Endpunkt angeben – /answers, angehängt an die Basis-URL https://api.stackexchange.com/2.2/ –, dann die Ergebnisse abrufen und in einer Recycler-Ansicht anzeigen. Ich zeige Ihnen auch, wie Sie dies mit RxJava tun, um den Status- und Datenfluss einfach zu verwalten.

1. Erstellen Sie ein Android Studio-Projekt

Starten Sie Android Studio und erstellen Sie ein neues Projekt mit einer leeren Aktivität namens MainActivity.

Create a new empty activityCreate a new empty activityCreate a new empty activity

2. Abhängigkeiten erklären

Deklarieren Sie nach dem Erstellen eines neuen Projekts die folgenden Abhängigkeiten in Ihrer build.gradle. Zu den Abhängigkeiten gehören eine Recycler-Ansicht, die Retrofit-Bibliothek sowie die Gson-Bibliothek von Google zur Konvertierung von JSON in POJO (Plain Old Java Objects) sowie die Gson-Integration von Retrofit.

1
// Retrofit

2
compile 'com.squareup.retrofit2:retrofit:2.1.0'
3
4
// JSON Parsing

5
compile 'com.google.code.gson:gson:2.6.1'
6
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
7
8
// recyclerview 

9
compile 'com.android.support:recyclerview-v7:25.0.1'

Vergessen Sie nicht, das Projekt zu synchronisieren, um diese Bibliotheken herunterzuladen.

3. Internetberechtigung hinzufügen

Um Netzwerkvorgänge durchzuführen, müssen wir die INTERNET-Berechtigung in das Anwendungsmanifest aufnehmen: AndroidManifest.xml.

1
<?xml version="1.0" encoding="utf-8"?>
2
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
          package="com.chikeandroid.retrofittutorial">
4
5
    <uses-permission android:name="android.permission.INTERNET" />
6
7
    <application
8
            android:allowBackup="true"
9
            android:icon="@mipmap/ic_launcher"
10
            android:label="@string/app_name"
11
            android:supportsRtl="true"
12
            android:theme="@style/AppTheme">
13
        <activity android:name=".MainActivity">
14
            <intent-filter>
15
                <action android:name="android.intent.action.MAIN"/>
16
17
                <category android:name="android.intent.category.LAUNCHER"/>
18
            </intent-filter>
19
        </activity>
20
    </application>
21
22
</manifest>

4. Modelle automatisch generieren

Wir werden unsere Modelle automatisch aus unseren JSON-Antwortdaten erstellen, indem wir ein sehr nützliches Tool nutzen: jsonschema2pojo.

Holen Sie sich die JSON-Beispieldaten

Kopieren Sie https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow und fügen Sie sie in die Adressleiste Ihres Browsers ein (oder Sie können Postman verwenden, wenn Sie mit diesem Tool vertraut sind). Drücken Sie dann die Eingabetaste – dies führt eine GET-Anfrage auf dem angegebenen Endpunkt aus. Als Antwort sehen Sie ein Array von JSON-Objekten. Der Screenshot unten ist die JSON-Antwort mit Postman.

API response to GET requestAPI response to GET requestAPI response to GET request
1
{
2
  "items": [
3
    {
4
      "owner": {
5
        "reputation": 1,
6
        "user_id": 6540831,
7
        "user_type": "registered",
8
        "profile_image": "https://www.gravatar.com/avatar/6a468ce8a8ff42c17923a6009ab77723?s=128&d=identicon&r=PG&f=1",
9
        "display_name": "bobolafrite",
10
        "link": "http://stackoverflow.com/users/6540831/bobolafrite"
11
      },
12
      "is_accepted": false,
13
      "score": 0,
14
      "last_activity_date": 1480862271,
15
      "creation_date": 1480862271,
16
      "answer_id": 40959732,
17
      "question_id": 35931342
18
    },
19
    {
20
      "owner": {
21
        "reputation": 629,
22
        "user_id": 3054722,
23
        "user_type": "registered",
24
        "profile_image": "https://www.gravatar.com/avatar/0cf65651ae9a3ba2858ef0d0a7dbf900?s=128&d=identicon&r=PG&f=1",
25
        "display_name": "jeremy-denis",
26
        "link": "http://stackoverflow.com/users/3054722/jeremy-denis"
27
      },
28
      "is_accepted": false,
29
      "score": 0,
30
      "last_activity_date": 1480862260,
31
      "creation_date": 1480862260,
32
      "answer_id": 40959731,
33
      "question_id": 40959661
34
    },
35
    ...
36
  ],
37
  "has_more": true,
38
  "backoff": 10,
39
  "quota_max": 300,
40
  "quota_remaining": 241
41
}

Kopieren Sie diese JSON-Antwort entweder von Ihrem Browser oder Postman.

Ordnen Sie die JSON-Daten Java zu

Rufen Sie nun jsonschema2pojo auf und fügen Sie die JSON-Antwort in das Eingabefeld ein.

Wählen Sie einen Quelltyp von JSON, einen Anmerkungsstil von Gson und deaktivieren Sie das Kontrollkästchen Zusätzliche Eigenschaften zulassen.

jsonschema2pojo interfacejsonschema2pojo interfacejsonschema2pojo interface

Klicken Sie dann auf die Schaltfläche Vorschau, um die Java-Objekte zu generieren.

jsonschema2pojo outputjsonschema2pojo outputjsonschema2pojo output

Sie fragen sich vielleicht, was die Annotationen @SerializedName und @Expose in diesem generierten Code bewirken. Keine Sorge, ich erkläre alles!

Die Annotation @SerializedName wird benötigt, damit Gson die JSON-Schlüssel unseren Feldern zuordnet. In Übereinstimmung mit der camelCase-Namenskonvention von Java für Klassenmembereigenschaften wird davon abgeraten, Unterstriche zum Trennen von Wörtern in einer Variablen zu verwenden. @SerializedName hilft bei der Übersetzung zwischen den beiden.

1
@SerializedName("quota_remaining")
2
@Expose
3
private Integer quotaRemaining;

Im obigen Beispiel teilen wir Gson mit, dass unser JSON-Schlüssel quota_remaining dem Java-Feld quotaRemaining zugeordnet werden soll. Wenn diese beiden Werte gleich wären, d. h. wenn unser JSON-Schlüssel quotaRemaining genau wie das Java-Feld wäre, dann wäre die Annotation @SerializedName für das Feld nicht erforderlich, da Gson sie automatisch zuordnen würde.

Die Annotation @Expose gibt an, dass dieser Member für die JSON-Serialisierung oder -Deserialisierung verfügbar gemacht werden soll.

Datenmodelle in Android Studio importieren

Kehren wir nun zu Android Studio zurück. Erstellen Sie ein neues Unterpaket innerhalb des Hauptpakets und nennen Sie es data. Erstellen Sie innerhalb des neu erstellten Datenpakets ein weiteres Paket und nennen Sie es model. Erstellen Sie im Modellpaket eine neue Java-Klasse und nennen Sie sie Owner. Kopieren Sie nun die von jsonschema2pojo generierte Owner-Klasse und fügen Sie sie in die von Ihnen erstellte Owner-Klasse ein.

1
import com.google.gson.annotations.Expose;
2
import com.google.gson.annotations.SerializedName;
3
4
public class Owner {
5
6
    @SerializedName("reputation")
7
    @Expose
8
    private Integer reputation;
9
    @SerializedName("user_id")
10
    @Expose
11
    private Integer userId;
12
    @SerializedName("user_type")
13
    @Expose
14
    private String userType;
15
    @SerializedName("profile_image")
16
    @Expose
17
    private String profileImage;
18
    @SerializedName("display_name")
19
    @Expose
20
    private String displayName;
21
    @SerializedName("link")
22
    @Expose
23
    private String link;
24
    @SerializedName("accept_rate")
25
    @Expose
26
    private Integer acceptRate;
27
28
29
    public Integer getReputation() {
30
        return reputation;
31
    }
32
33
    public void setReputation(Integer reputation) {
34
        this.reputation = reputation;
35
    }
36
37
    public Integer getUserId() {
38
        return userId;
39
    }
40
41
    public void setUserId(Integer userId) {
42
        this.userId = userId;
43
    }
44
45
    public String getUserType() {
46
        return userType;
47
    }
48
49
    public void setUserType(String userType) {
50
        this.userType = userType;
51
    }
52
53
    public String getProfileImage() {
54
        return profileImage;
55
    }
56
57
    public void setProfileImage(String profileImage) {
58
        this.profileImage = profileImage;
59
    }
60
61
    public String getDisplayName() {
62
        return displayName;
63
    }
64
65
    public void setDisplayName(String displayName) {
66
        this.displayName = displayName;
67
    }
68
69
    public String getLink() {
70
        return link;
71
    }
72
73
    public void setLink(String link) {
74
        this.link = link;
75
    }
76
77
    public Integer getAcceptRate() {
78
        return acceptRate;
79
    }
80
81
    public void setAcceptRate(Integer acceptRate) {
82
        this.acceptRate = acceptRate;
83
    }
84
}

Machen Sie dasselbe für eine neue Item-Klasse, die aus jsonschema2pojo kopiert wurde.

1
import com.google.gson.annotations.Expose;
2
import com.google.gson.annotations.SerializedName;
3
4
public class Item {
5
6
    @SerializedName("owner")
7
    @Expose
8
    private Owner owner;
9
    @SerializedName("is_accepted")
10
    @Expose
11
    private Boolean isAccepted;
12
    @SerializedName("score")
13
    @Expose
14
    private Integer score;
15
    @SerializedName("last_activity_date")
16
    @Expose
17
    private Integer lastActivityDate;
18
    @SerializedName("creation_date")
19
    @Expose
20
    private Integer creationDate;
21
    @SerializedName("answer_id")
22
    @Expose
23
    private Integer answerId;
24
    @SerializedName("question_id")
25
    @Expose
26
    private Integer questionId;
27
    @SerializedName("last_edit_date")
28
    @Expose
29
    private Integer lastEditDate;
30
31
    public Owner getOwner() {
32
        return owner;
33
    }
34
35
    public void setOwner(Owner owner) {
36
        this.owner = owner;
37
    }
38
39
    public Boolean getIsAccepted() {
40
        return isAccepted;
41
    }
42
43
    public void setIsAccepted(Boolean isAccepted) {
44
        this.isAccepted = isAccepted;
45
    }
46
47
    public Integer getScore() {
48
        return score;
49
    }
50
51
    public void setScore(Integer score) {
52
        this.score = score;
53
    }
54
55
    public Integer getLastActivityDate() {
56
        return lastActivityDate;
57
    }
58
59
    public void setLastActivityDate(Integer lastActivityDate) {
60
        this.lastActivityDate = lastActivityDate;
61
    }
62
63
    public Integer getCreationDate() {
64
        return creationDate;
65
    }
66
67
    public void setCreationDate(Integer creationDate) {
68
        this.creationDate = creationDate;
69
    }
70
    
71
    public Integer getAnswerId() {
72
        return answerId;
73
    }
74
75
    public void setAnswerId(Integer answerId) {
76
        this.answerId = answerId;
77
    }
78
79
    public Integer getQuestionId() {
80
        return questionId;
81
    }
82
83
    public void setQuestionId(Integer questionId) {
84
        this.questionId = questionId;
85
    }
86
87
    public Integer getLastEditDate() {
88
        return lastEditDate;
89
    }
90
91
    public void setLastEditDate(Integer lastEditDate) {
92
        this.lastEditDate = lastEditDate;
93
    }
94
}

Erstellen Sie schließlich eine Klasse namens SOAnswersResponse für die zurückgegebenen StackOverflow-Antworten. Den Code für diese Klasse finden Sie in jsonschema2pojo als Example. Stellen Sie sicher, dass Sie den Klassennamen überall auf SOAnswersResponse aktualisieren.

1
import com.google.gson.annotations.Expose;
2
import com.google.gson.annotations.SerializedName;
3
4
import java.util.List;
5
6
public class SOAnswersResponse {
7
8
    @SerializedName("items")
9
    @Expose
10
    private List<Item> items = null;
11
    @SerializedName("has_more")
12
    @Expose
13
    private Boolean hasMore;
14
    @SerializedName("backoff")
15
    @Expose
16
    private Integer backoff;
17
    @SerializedName("quota_max")
18
    @Expose
19
    private Integer quotaMax;
20
    @SerializedName("quota_remaining")
21
    @Expose
22
    private Integer quotaRemaining;
23
24
    public List<Item> getItems() {
25
        return items;
26
    }
27
28
    public void setItems(List<Item> items) {
29
        this.items = items;
30
    }
31
32
    public Boolean getHasMore() {
33
        return hasMore;
34
    }
35
36
    public void setHasMore(Boolean hasMore) {
37
        this.hasMore = hasMore;
38
    }
39
40
    public Integer getBackoff() {
41
        return backoff;
42
    }
43
44
    public void setBackoff(Integer backoff) {
45
        this.backoff = backoff;
46
    }
47
48
    public Integer getQuotaMax() {
49
        return quotaMax;
50
    }
51
52
    public void setQuotaMax(Integer quotaMax) {
53
        this.quotaMax = quotaMax;
54
    }
55
56
    public Integer getQuotaRemaining() {
57
        return quotaRemaining;
58
    }
59
60
    public void setQuotaRemaining(Integer quotaRemaining) {
61
        this.quotaRemaining = quotaRemaining;
62
    }
63
}

5. Erstellen der Retrofit-Instanz

Um mit Retrofit Netzwerkanforderungen an eine REST-API zu senden, müssen wir eine Instanz mit der Retrofit.Builder-Klasse erstellen und sie mit einer Basis-URL konfigurieren.

Erstellen Sie ein neues Unterpaketpaket innerhalb des data-Pakets und nennen Sie es remote. Erstellen Sie nun in remote eine Java-Klasse und nennen Sie sie RetrofitClient. Diese Klasse erstellt ein Singleton von Retrofit. Retrofit benötigt eine Basis-URL, um seine Instanz zu erstellen, daher übergeben wir beim Aufrufen von RetrofitClient.getClient(String baseUrl) eine URL. Diese URL wird dann verwendet, um die Instanz in Zeile 13 zu erstellen. Außerdem geben wir in Zeile 14 den von uns benötigten JSON-Konverter (Gson) an.

1
import retrofit2.Retrofit;
2
import retrofit2.converter.gson.GsonConverterFactory;
3
4
public class RetrofitClient {
5
6
    private static Retrofit retrofit = null;
7
8
    public static Retrofit getClient(String baseUrl) {
9
        if (retrofit==null) {
10
            retrofit = new Retrofit.Builder()
11
                    .baseUrl(baseUrl)
12
                    .addConverterFactory(GsonConverterFactory.create())
13
                    .build();
14
        }
15
        return retrofit;
16
    }
17
}

6. Erstellen der API-Schnittstelle

Erstellen Sie innerhalb des Remote-Pakets eine Schnittstelle und nennen Sie sie SOService. Diese Schnittstelle enthält Methoden, die wir verwenden werden, um HTTP-Anforderungen wie GET, POST, PUT, PATCH und DELETE auszuführen. Für dieses Tutorial werden wir eine GET-Anfrage ausführen.

1
import com.chikeandroid.retrofittutorial.data.model.SOAnswersResponse;
2
3
import java.util.List;
4
5
import retrofit2.Call;
6
import retrofit2.http.GET;
7
8
public interface SOService {
9
10
   @GET("/answers?order=desc&sort=activity&site=stackoverflow")
11
   Call<List<SOAnswersResponse>> getAnswers(); 
12
    
13
   @GET("/answers?order=desc&sort=activity&site=stackoverflow")
14
   Call<List<SOAnswersResponse>> getAnswers(@Query("tagged") String tags);
15
}

Die Annotation @GET definiert explizit die GET-Anforderung, die ausgeführt wird, sobald die Methode aufgerufen wird. Jede Methode in dieser Schnittstelle muss eine HTTP-Annotation haben, die die Anforderungsmethode und die relative URL bereitstellt. Es stehen fünf integrierte Anmerkungen zur Verfügung: @GET, @POST, @PUT, @DELETE und @HEAD.

In der zweiten Methodendefinition haben wir einen Abfrageparameter hinzugefügt, damit wir die Daten vom Server filtern können. Retrofit hat die Annotation @Query("key"), die verwendet wird, anstatt sie im Endpunkt fest zu codieren. Der Schlüsselwert stellt den Parameternamen in der URL dar. Es wird der URL von Retrofit hinzugefügt. Wenn wir beispielsweise den Wert "android" als Argument an die Methode getAnswers(String tags) übergeben, lautet die vollständige URL:

1
https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow&tagged=android

Parameter der Schnittstellenmethoden können folgende Annotationen haben:

@Path Variablensubstitution für den API-Endpunkt
@Query gibt den Abfrageschlüsselnamen mit dem Wert des annotierten Parameters an
@Body Nutzlast für den POST-Aufruf
@Header spezifiziert den Header mit dem Wert des annotierten Parameters

7. Erstellen der API-Utilities

Jetzt erstellen Sie eine Dienstprogrammklasse. Wir nennen es ApiUtils. Diese Klasse hat die Basis-URL als statische Variable und stellt unserer Anwendung über die statische Methode getSOService() auch die SOService-Schnittstelle zur Verfügung.

1
public class ApiUtils {
2
3
    public static final String BASE_URL = "https://api.stackexchange.com/2.2";
4
5
    public static SOService getSOService() {
6
        return RetrofitClient.getClient(BASE_URL).create(SOService.class);
7
    }
8
}

8. Anzeige auf einem RecyclerView

Da die Ergebnisse in einer Recycler-Ansicht angezeigt werden, benötigen wir einen Adapter. Der folgende Codeausschnitt zeigt die AnswersAdapter-Klasse.

1
public class AnswersAdapter extends RecyclerView.Adapter<AnswersAdapter.ViewHolder> {
2
3
    private List<Item> mItems;
4
    private Context mContext;
5
    private PostItemListener mItemListener;
6
7
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
8
9
        public TextView titleTv;
10
        PostItemListener mItemListener;
11
12
        public ViewHolder(View itemView, PostItemListener postItemListener) {
13
            super(itemView);
14
            titleTv = (TextView) itemView.findViewById(android.R.id.text1);
15
16
            this.mItemListener = postItemListener;
17
            itemView.setOnClickListener(this);
18
        }
19
20
        @Override
21
        public void onClick(View view) {
22
            Item item = getItem(getAdapterPosition());
23
            this.mItemListener.onPostClick(item.getAnswerId());
24
25
            notifyDataSetChanged();
26
        }
27
    }
28
29
    public AnswersAdapter(Context context, List<Item> posts, PostItemListener itemListener) {
30
        mItems = posts;
31
        mContext = context;
32
        mItemListener = itemListener;
33
    }
34
35
    @Override
36
    public AnswersAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
37
38
        Context context = parent.getContext();
39
        LayoutInflater inflater = LayoutInflater.from(context);
40
41
        View postView = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
42
43
        ViewHolder viewHolder = new ViewHolder(postView, this.mItemListener);
44
        return viewHolder;
45
    }
46
47
    @Override
48
    public void onBindViewHolder(AnswersAdapter.ViewHolder holder, int position) {
49
50
        Item item = mItems.get(position);
51
        TextView textView = holder.titleTv;
52
        textView.setText(item.getOwner().getDisplayName());
53
    }
54
55
    @Override
56
    public int getItemCount() {
57
        return mItems.size();
58
    }
59
60
    public void updateAnswers(List<Item> items) {
61
        mItems = items;
62
        notifyDataSetChanged();
63
    }
64
65
    private Item getItem(int adapterPosition) {
66
        return mItems.get(adapterPosition);
67
    }
68
69
    public interface PostItemListener {
70
        void onPostClick(long id);
71
    }
72
}

9. Ausführen der Anfrage

Innerhalb der Methode onCreate() der MainActivity initialisieren wir eine Instanz der SOService-Schnittstelle (Zeile 9), die Recycler-Ansicht und auch den Adapter. Schließlich rufen wir die Methode loadAnswers() auf.

1
 private AnswersAdapter mAdapter;
2
    private RecyclerView mRecyclerView;
3
    private SOService mService;
4
5
    @Override
6
    protected void onCreate (Bundle savedInstanceState)  {
7
        super.onCreate( savedInstanceState );
8
        setContentView(R.layout.activity_main );
9
        mService = ApiUtils.getSOService();
10
        mRecyclerView = (RecyclerView) findViewById(R.id.rv_answers);
11
        mAdapter = new AnswersAdapter(this, new ArrayList<Item>(0), new AnswersAdapter.PostItemListener() {
12
13
            @Override
14
            public void onPostClick(long id) {
15
                Toast.makeText(MainActivity.this, "Post id is" + id, Toast.LENGTH_SHORT).show();
16
            }
17
        });
18
19
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
20
        mRecyclerView.setLayoutManager(layoutManager);
21
        mRecyclerView.setAdapter(mAdapter);
22
        mRecyclerView.setHasFixedSize(true);
23
        RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
24
        mRecyclerView.addItemDecoration(itemDecoration);
25
26
        loadAnswers();
27
    }

Die Methode loadAnswers() stellt eine Netzwerkanfrage, indem sie enqueue() aufruft. Wenn die Antwort zurückkommt, hilft uns Retrofit, die JSON-Antwort auf eine Liste von Java-Objekten zu analysieren. (Dies wird durch die Verwendung von GsonConverter ermöglicht.)

1
public void loadAnswers() {
2
    mService.getAnswers().enqueue(new Callback<SOAnswersResponse>() {
3
    @Override
4
    public void onResponse(Call<SOAnswersResponse> call, Response<SOAnswersResponse> response) {
5
6
        if(response.isSuccessful()) {
7
            mAdapter.updateAnswers(response.body().getItems());
8
            Log.d("MainActivity", "posts loaded from API");
9
        }else {
10
            int statusCode  = response.code();
11
            // handle request errors depending on status code

12
        }
13
    }
14
15
    @Override
16
    public void onFailure(Call<SOAnswersResponse> call, Throwable t) {
17
       showErrorMessage();
18
        Log.d("MainActivity", "error loading from API");
19
20
    }
21
});
22
}

10. enqueue() verstehen

enqueue() sendet die Anfrage asynchron und benachrichtigt Ihre App mit einem Rückruf, wenn eine Antwort zurückkommt. Da diese Anforderung asynchron ist, verarbeitet Retrofit sie in einem Hintergrundthread, damit der Haupt-UI-Thread nicht blockiert oder gestört wird.

Um enqueue() zu verwenden, müssen Sie zwei Callback-Methoden implementieren:

  • onResponse()
  • onFailure()

Als Antwort auf eine bestimmte Anforderung wird nur eine dieser Methoden aufgerufen.

  • onResponse(): wird für eine empfangene HTTP-Antwort aufgerufen. Diese Methode wird für eine Antwort aufgerufen, die auch dann korrekt verarbeitet werden kann, wenn der Server eine Fehlermeldung zurückgibt. Wenn Sie also einen Statuscode von 404 oder 500 erhalten, wird diese Methode trotzdem aufgerufen. Um den Statuscode zu erhalten, damit Sie darauf basierende Situationen handhaben können, können Sie die Methode response.code() verwenden. Sie können auch die Methode isSuccessful() verwenden, um herauszufinden, ob der Statuscode im Bereich von 200 bis 300 liegt und den Erfolg anzeigt.
  • onFailure(): wird aufgerufen, wenn eine Netzwerkausnahme bei der Kommunikation mit dem Server aufgetreten ist oder wenn eine unerwartete Ausnahme bei der Verarbeitung der Anfrage oder der Verarbeitung der Antwort aufgetreten ist.

Um eine synchrone Anfrage auszuführen, können Sie die Methode execute() verwenden. Beachten Sie, dass synchrone Methoden im Haupt-/UI-Thread jede Benutzeraktion blockieren. Führen Sie also keine synchronen Methoden im Haupt-/UI-Thread von Android aus! Führen Sie sie stattdessen in einem Hintergrundthread aus.

11. Testen der App

Sie können die App jetzt ausführen.

Sample results from StackOverflowSample results from StackOverflowSample results from StackOverflow

12. RxJava-Integration

Wenn Sie ein Fan von RxJava sind, können Sie Retrofit mit RxJava problemlos implementieren. In Retrofit 1 war es standardmäßig integriert, aber in Retrofit 2 müssen Sie einige zusätzliche Abhängigkeiten einbeziehen. Retrofit wird mit einem Standardadapter zum Call von Anrufinstanzen geliefert. Sie können also den Ausführungsmechanismus von Retrofit so ändern, dass er RxJava enthält, indem Sie den RxJava CallAdapter einbinden.

Schritt 1

Fügen Sie die Abhängigkeiten hinzu.

1
compile 'io.reactivex:rxjava:1.1.6'
2
compile 'io.reactivex:rxandroid:1.2.1'
3
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

Schritt 2

Fügen Sie beim Erstellen einer Retrofit-Instanz den neuen CallAdapter RxJavaCallAdapterFactory.create() hinzu.

1
public static Retrofit getClient(String baseUrl) {
2
    if (retrofit==null) {
3
        retrofit = new Retrofit.Builder()
4
                .baseUrl(baseUrl)
5
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
6
                .addConverterFactory(GsonConverterFactory.create())
7
                .build();
8
    }
9
    return retrofit;
10
}

Schritt 3

Beim Stellen der Anfragen antwortet unser anonymer Abonnent auf den Stream des Observables, der Ereignisse ausgibt, in unserem Fall SOAnswersResponse. Die onNext-Methode wird dann aufgerufen, wenn unser Abonnent ein ausgegebenes Ereignis empfängt, das dann an unseren Adapter übergeben wird.

1
@Override
2
public void loadAnswers() {
3
    mService.getAnswers().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
4
            .subscribe(new Subscriber<SOAnswersResponse>() {
5
                @Override
6
                public void onCompleted() {
7
8
                }
9
10
                @Override
11
                public void onError(Throwable e) {
12
13
                }
14
15
                @Override
16
                public void onNext(SOAnswersResponse soAnswersResponse) {
17
                    mAdapter.updateAnswers(soAnswersResponse.getItems());
18
                }
19
            });
20
}

Sehen Sie sich Erste Schritte mit ReactiveX auf Android von Ashraff Hathibelagal an, um mehr über RxJava und RxAndroid zu erfahren.

Abschluss

In diesem Tutorial haben Sie Retrofit kennengelernt: warum und wie Sie es verwenden sollten. Ich habe auch erklärt, wie man die RxJava-Integration mit Retrofit hinzufügt. In meinem nächsten Beitrag zeige ich Ihnen, wie Sie POST, PUT und DELETE ausführen, wie Sie Form-Urlencoded Daten senden und wie Sie Anfragen abbrechen.

Weitere Informationen zu Retrofit finden Sie in der offiziellen Dokumentation. Sehen Sie sich in der Zwischenzeit einige unserer anderen Kurse und Tutorials zur Android-App-Entwicklung an.