Retrofit Android 예제 튜토리얼에 오신 것을 환영합니다. 오늘은 안드로이드 애플리케이션에서 REST API 호출을 처리하기 위해 Square에서 개발한 Retrofit 라이브러리를 사용할 것입니다.
Retrofit Android
Retrofit은 안드로이드와 자바용으로 제작된 타입 안전한 REST 클라이언트로, RESTful 웹 서비스를 소비하기 쉽도록하는 것을 목표로 합니다. 우리는 Retrofit 1.x 버전의 세부 사항에 대해 다루지 않고 이전 버전과 비교하여 많은 새로운 기능과 변경된 내부 API를 가진 Retrofit 2로 바로 넘어가겠습니다. Retrofit 2는 기본적으로 OkHttp를 네트워킹 레이어로 사용하며 이 위에 구축되었습니다. Retrofit은 POJO(Plain Old Java Object)를 사용하여 JSON 응답을 자동으로 직렬화합니다. 이를 위해 JSON을 Gson으로 먼저 변환해야 합니다. build.gradle
파일에 다음 종속성을 추가해야 합니다.
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
OkHttp 종속성은 이미 Retrofit 2 종속성과 함께 제공됩니다. 별도의 OkHttp 종속성을 사용하려는 경우 Retrofit 2에서 OkHttp 종속성을 제외해야 합니다. 다음과 같이 진행할 수 있습니다:
compile ('com.squareup.retrofit2:retrofit:2.1.0') {
// Retrofit의 OkHttp 종속성 모듈을 제외하고 직접 모듈을 정의합니다
exclude module: 'okhttp'
}
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttps:3.4.1'
- logging-interceptor는 반환된 전체 응답의 로그 문자열을 생성합니다.
- JSON을 필요한 유형으로 파싱하기 위한 다른 변환기가 있습니다. 이 중 일부는 아래에 나열되어 있습니다.
- Jackson :
com.squareup.retrofit2:converter-jackson:2.1.0
- Moshi :
com.squareup.retrofit2:converter-moshi:2.1.0
- Protobuf :
com.squareup.retrofit2:converter-protobuf:2.1.0
- Wire :
com.squareup.retrofit2:converter-wire:2.1.0
- Simple XML :
com.squareup.retrofit2:converter-simplexml:2.1.0
AndroidManifest.xml 파일에서 인터넷 접근 권한을 추가합니다.
OkHttp Interceptors
인터셉터는 OkHttp에 있는 강력한 메커니즘으로 호출을 모니터링, 재작성 및 재시도할 수 있습니다. 인터셉터는 주로 두 가지 범주로 나뉩니다:
- 애플리케이션 인터셉터 : 애플리케이션 인터셉터를 등록하려면
OkHttpClient.Builder
에서addInterceptor()
를 호출해야 합니다. - 네트워크 인터셉터 : 네트워크 인터셉터를 등록하려면
addInterceptor()
대신에addNetworkInterceptor()
를 호출합니다.
Retrofit 인터페이스 설정
package com.journaldev.retrofitintro;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
class APIClient {
private static Retrofit retrofit = null;
static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
위의 코드의 getClient()
메서드는 Retrofit 인터페이스를 설정할 때마다 호출됩니다. Retrofit은 각 HTTP 메서드에 대한 주석 목록을 제공합니다: @GET, @POST, @PUT, @DELETE, @PATCH 또는 @HEAD
. 이제 우리의 APIInterface.java
클래스를 살펴보겠습니다.
package com.journaldev.retrofitintro;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import com.journaldev.retrofitintro.pojo.User;
import com.journaldev.retrofitintro.pojo.UserList;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
interface APIInterface {
@GET("/api/unknown")
Call<MultipleResource> doGetListResources();
@POST("/api/users")
Call<User> createUser(@Body User user);
@GET("/api/users?")
Call<UserList> doGetUserList(@Query("page") String page);
@FormUrlEncoded
@POST("/api/users?")
Call<UserList> doCreateUserWithField(@Field("name") String name, @Field("job") String job);
}
위의 클래스에서는 주석으로 HTTP 요청을 수행하는 몇 가지 메서드를 정의했습니다. @GET("/api/unknown")
는 doGetListResources();
를 호출합니다. doGetListResources()
는 메서드 이름입니다. MultipleResource.java
는 응답 객체에 대한 모델 POJO 클래스로, 응답 매개변수를 해당 변수에 매핑하는 데 사용됩니다. 이러한 POJO 클래스는 메서드의 반환 유형으로 작동합니다. MultipleResources.java
에 대한 간단한 POJO 클래스는 다음과 같습니다.
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class MultipleResource {
@SerializedName("page")
public Integer page;
@SerializedName("per_page")
public Integer perPage;
@SerializedName("total")
public Integer total;
@SerializedName("total_pages")
public Integer totalPages;
@SerializedName("data")
public List<Datum> data = null;
public class Datum {
@SerializedName("id")
public Integer id;
@SerializedName("name")
public String name;
@SerializedName("year")
public Integer year;
@SerializedName("pantone_value")
public String pantoneValue;
}
}
@SerializedName
주석은 JSON 응답에 있는 필드의 이름을 지정하는 데 사용됩니다. POJO 클래스를 미리보고 Android Studio 프로젝트 구조에 복사하십시오. POJO 클래스는 타입이 지정된 Retrofit
Call
클래스로 래핑됩니다. 참고: JSONArray는 POJO 클래스의 객체 목록으로 직렬화됩니다. 메서드 매개변수: 메서드 내부에 전달할 수 있는 매개변수의 다양한 옵션이 있습니다:
@Body
– Java 객체를 요청 본문으로 보냅니다.@Url
– 동적 URL을 사용합니다.@Query
– 우리는 매개변수에 @Query와 쿼리 매개변수 이름을 추가하여 간단히 메소드를 추가할 수 있습니다. 쿼리를 URL 인코딩하려면 다음과 같이 사용합니다:@Query(value = "auth_token",encoded = true) String auth_token
@Field
– 데이터를 form-urlencoded로 전송합니다. 이는 메소드와 연결된@FormUrlEncoded
어노테이션을 필요로 합니다.@Field
매개변수는 POST와 함께만 작동합니다.
Note: @Field는 필수 매개변수를 요구합니다. @Field가 선택적인 경우 @Query를 대신 사용하고 null 값을 전달할 수 있습니다.
Retrofit Android 예제 프로젝트 구조
pojo 패키지는 APIInterface.java 클래스에서 정의된 각 API 엔드포인트 응답에 대한 네 가지 모델 클래스를 정의합니다.
User.java
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("name")
public String name;
@SerializedName("job")
public String job;
@SerializedName("id")
public String id;
@SerializedName("createdAt")
public String createdAt;
public User(String name, String job) {
this.name = name;
this.job = job;
}
}
위 클래스는 createUser()
메소드의 응답 본문을 생성하는 데 사용됩니다. UserList.java
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class UserList {
@SerializedName("page")
public Integer page;
@SerializedName("per_page")
public Integer perPage;
@SerializedName("total")
public Integer total;
@SerializedName("total_pages")
public Integer totalPages;
@SerializedName("data")
public List<Datum> data = new ArrayList();
public class Datum {
@SerializedName("id")
public Integer id;
@SerializedName("first_name")
public String first_name;
@SerializedName("last_name")
public String last_name;
@SerializedName("avatar")
public String avatar;
}
}
CreateUserResponse.java
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
public class CreateUserResponse {
@SerializedName("name")
public String name;
@SerializedName("job")
public String job;
@SerializedName("id")
public String id;
@SerializedName("createdAt")
public String createdAt;
}
MainActivity.java
은 인터페이스 클래스에서 정의된 각 API 엔드포인트를 호출하고 각 필드를 Toast/TextView에 표시하는 곳입니다.
package com.journaldev.retrofitintro;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.journaldev.retrofitintro.pojo.CreateUserResponse;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import com.journaldev.retrofitintro.pojo.User;
import com.journaldev.retrofitintro.pojo.UserList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
TextView responseText;
APIInterface apiInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
responseText = (TextView) findViewById(R.id.responseText);
apiInterface = APIClient.getClient().create(APIInterface.class);
/**
GET List Resources
**/
Call<MultipleResource> call = apiInterface.doGetListResources();
call.enqueue(new Callback<MultipleResource>() {
@Override
public void onResponse(Call<MultipleResource> call, Response<MultipleResource> response) {
Log.d("TAG",response.code()+"");
String displayResponse = "";
MultipleResource resource = response.body();
Integer text = resource.page;
Integer total = resource.total;
Integer totalPages = resource.totalPages;
List<MultipleResource.Datum> datumList = resource.data;
displayResponse += text + " Page\n" + total + " Total\n" + totalPages + " Total Pages\n";
for (MultipleResource.Datum datum : datumList) {
displayResponse += datum.id + " " + datum.name + " " + datum.pantoneValue + " " + datum.year + "\n";
}
responseText.setText(displayResponse);
}
@Override
public void onFailure(Call<MultipleResource> call, Throwable t) {
call.cancel();
}
});
/**
Create new user
**/
User user = new User("morpheus", "leader");
Call<User> call1 = apiInterface.createUser(user);
call1.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
User user1 = response.body();
Toast.makeText(getApplicationContext(), user1.name + " " + user1.job + " " + user1.id + " " + user1.createdAt, Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<User> call, Throwable t) {
call.cancel();
}
});
/**
GET List Users
**/
Call<UserList> call2 = apiInterface.doGetUserList("2");
call2.enqueue(new Callback<UserList>() {
@Override
public void onResponse(Call<UserList> call, Response<UserList> response) {
UserList userList = response.body();
Integer text = userList.page;
Integer total = userList.total;
Integer totalPages = userList.totalPages;
List<UserList.Datum> datumList = userList.data;
Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();
for (UserList.Datum datum : datumList) {
Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<UserList> call, Throwable t) {
call.cancel();
}
});
/**
POST name and job Url encoded.
**/
Call<UserList> call3 = apiInterface.doCreateUserWithField("morpheus","leader");
call3.enqueue(new Callback<UserList>() {
@Override
public void onResponse(Call<UserList> call, Response<UserList> response) {
UserList userList = response.body();
Integer text = userList.page;
Integer total = userList.total;
Integer totalPages = userList.totalPages;
List<UserList.Datum> datumList = userList.data;
Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();
for (UserList.Datum datum : datumList) {
Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<UserList> call, Throwable t) {
call.cancel();
}
});
}
}
apiInterface = APIClient.getClient().create(APIInterface.class);
는 APIClient를 인스턴스화하는 데 사용됩니다. 모델 클래스를 응답에 매핑하기 위해 우리는 다음을 사용합니다: MultipleResource resource = response.body();
애플리케이션을 실행하면 각 엔드포인트를 호출하고 각각에 대한 메시지를 Toast로 표시합니다. 이로써 Retrofit 안드로이드 예제 자습서가 끝납니다. 아래 링크에서 안드로이드 Retrofit 예제 프로젝트를 다운로드할 수 있습니다.
Source:
https://www.digitalocean.com/community/tutorials/retrofit-android-example-tutorial