Retrofit은 오픈 소스 기반의 회사인 Square에서 운영하는 Http 통신 오픈 소스 라이브러리입니다.
구글 문서에도 강력 추천하고 있고, nowInAndroid 안드로이드 샘플에서도 Retrofit을 사용해 네트워크 모듈을 구현한 것을 확인할 수 있습니다. 그만큼 Android 개발 생태계에서 필수(?) 라이브러리로 자리 잡았다고 생각이 드네요.
이번 글에서는 Retrofit의 사용 방법을 간략히 알아보겠습니다.
Retrofit
https://github.com/square/retrofit
GitHub - square/retrofit: A type-safe HTTP client for Android and the JVM
A type-safe HTTP client for Android and the JVM. Contribute to square/retrofit development by creating an account on GitHub.
github.com
Retrofit는 오픈 소스라고 소개드린 것처럼 Github에 Public repository로 공개되어 있습니다. 모든 코드가 공개되어 있기 때문에 날 잡아서 코드를 분석해보고 싶지만 선뜻 시도하지 못하고 있네요. 흑흑
의존성을 추가하기 전, 지원하는 최신 버전 정보를 확인하는 것을 추천드립니다.
Retrofit 사용 방법
Retrofit의 사용 방법 설명은 nowInAndroid의 샘플 코드를 기반으로 시작하려고 합니다. 개발자 성향, 프로젝트 아키텍처에 따라서 다른 부분이 존재할 것으로 예상됩니다. 그래서 이 글도 정답은 아니며, 그저 하나의 예제로 참고해 주시면 감사하겠습니다.
직접 코드를 보실 분은 nowInAndroid 프로젝트의 core/network 모듈을 보시면 됩니다
OkHttpClient 및 Json Converter 생성
@Module
@InstallIn(SingletonComponent::class)
internal object NetworkModule {
@Provides
@Singleton
fun providesNetworkJson(): Json = Json {
ignoreUnknownKeys = true
}
...
@Provides
@Singleton
fun okHttpCallFactory(): Call.Factory = trace("NiaOkHttpClient") {
OkHttpClient.Builder()
.addInterceptor(
HttpLoggingInterceptor()
.apply {
if (BuildConfig.DEBUG) {
setLevel(HttpLoggingInterceptor.Level.BODY)
}
},
)
.build()
}
}
위 코드는 의존성 주입 라이브러리인 Hilt를 사용해서 OkhttpClient 객체와 kotlinx.serialization의 Json 객체를 생성하는 코드입니다.
간략한 Hilt 설명
우선 Hilt는 프로젝트에서 종속 항목 수동 삽입(의존성 주입)에서 객체 생성하는 상용구를 줄이는 도움을 주는 라이브러리입니다. Hilt의 라이브러리의 필요성은 이 문서에서 자세히 확인가능합니다
종속 항목이란, A 클래스에서 B 클래스가 사용된다면 B는 A의 종속 항목 클래스입니다.
Json
Retrofit은 기본적으로 Http 통신의 결과로 callable objects로 반환됩니다. 또한 요청의 body로는 ResponseBody라는 객체가 기본적으로 사용되죠.
callable objects 반환값은 콜백 형태로 값을 처리해야 한다는 점이 Kotlin과 맞지 않고, ResponseBody는 객체 생성 자체에서 오는 불편함이 있습니다.
그래서 Retrofit은 변환, 요청의 타입을 다른 타입으로 변경시켜 줄 수 있는 Converter를 제공해 주는데요. 위 코드에서 생성하는 Json이 여기에 해당됩니다. 실제로 Retrofit에 설정하는 코드는 아래에 나옵니다!
REST API 인터페이스 작성
private interface RetrofitNiaNetworkApi {
@GET(value = "topics")
suspend fun getTopics(
@Query("id") ids: List<String>?,
): NetworkResponse<List<NetworkTopic>>
@GET(value = "newsresources")
suspend fun getNewsResources(
@Query("id") ids: List<String>?,
): NetworkResponse<List<NetworkNewsResource>>
@GET(value = "changelists/topics")
suspend fun getTopicChangeList(
@Query("after") after: Int?,
): List<NetworkChangeList>
@GET(value = "changelists/newsresources")
suspend fun getNewsResourcesChangeList(
@Query("after") after: Int?,
): List<NetworkChangeList>
}
이 코드는 Retrofit을 이용해서 REST API 인터페이스를 정의한 코드입니다.
REST API를 쉽게 정의할 수 있도록 GET, POST의 어노테이션을 제공해 줍니다. annotation의 매개변수로 end point를 명시할 수 있습니다. end point는 Retrofit 객체의 Base URL에 뒤에 붙어서 네트워크 통신을 위한 요청 url을 구성합니다.
위 코드에서 나오지 않았지만 @Header처럼 Retrofit에서 지원해 주는 annotation들을 확인해 보면 더 좋을 것 같습니다.
suspend function으로 api를 정의하면, 내부적으로 IOThread에서 동작하는 Job를 생성해서 네트워크 통신을 수행하게 됩니다.
Retrofit 객체 및 API 객체 생성
@Singleton
internal class RetrofitNiaNetwork @Inject constructor(
networkJson: Json,
okhttpCallFactory: dagger.Lazy<Call.Factory>,
) : NiaNetworkDataSource {
private val networkApi = trace("RetrofitNiaNetwork") {
Retrofit.Builder()
.baseUrl(NIA_BASE_URL)
// We use callFactory lambda here with dagger.Lazy<Call.Factory>
// to prevent initializing OkHttp on the main thread.
.callFactory { okhttpCallFactory.get().newCall(it) }
.addConverterFactory(
networkJson.asConverterFactory("application/json".toMediaType()),
)
.build()
.create(RetrofitNiaNetworkApi::class.java)
}
override suspend fun getTopics(ids: List<String>?): List<NetworkTopic> =
networkApi.getTopics(ids = ids).data
override suspend fun getNewsResources(ids: List<String>?): List<NetworkNewsResource> =
networkApi.getNewsResources(ids = ids).data
override suspend fun getTopicChangeList(after: Int?): List<NetworkChangeList> =
networkApi.getTopicChangeList(after = after)
override suspend fun getNewsResourceChangeList(after: Int?): List<NetworkChangeList> =
networkApi.getNewsResourcesChangeList(after = after)
}
이번 코드의 주요 코드는 Retrofit 객체 및 API 객체 생성입니다.
봐야 할 포인트 첫 번째는 dagger.Lazy로 지연 초기화해서 Call.Factory 객체의 의존성을 주입했다는 점입니다. 저도 이번에 처음 알게 된 지식이었는데요. Hilt로 인해서 어플레이케이션 생성이 되는 시점에 싱글톤으로 선언된 의존성 객체들을 생성이 될 수 있습니다. 해당 시점은 main thread에서 동작하므로 ANR을 주의해야 합니다.
Base URL, 그리고 Json과 CallFactory를 설정해서 생성한 Retrofit 객체의 create 함수를 통해 API 객체를 생성합니다.
create 함수는 매개변수로 넘겨받은 인터페이스 타입에 대해서 GET 등의 annotation들을 처리하고, 실제로 네트워크 통신 요청하는 코드들을 생성합니다. 내부 코드가 복잡하지만 엄청 자세하고 친절하게 소개된 개발 블로그를 소개합니다.
(Android) Retrofit2는 어떻게 동작하는가 — 1. 내부 코드 분석
Retrofit2 Deep Dive #1
medium.com
'Android > Common' 카테고리의 다른 글
[Android] 음성 인식 기능 추가하는 방법 정리 (0) | 2020.03.26 |
---|---|
[Android] AAC - View Binding (0) | 2020.03.12 |
[Android] Keybard Show/Hide 감지하기 (쉬움 주의) (0) | 2020.02.12 |
[Android] RecyclerView의 최상단 최하단 감지하기 (0) | 2020.02.10 |
[Android] Settings.Panel (0) | 2019.12.13 |
Retrofit은 오픈 소스 기반의 회사인 Square에서 운영하는 Http 통신 오픈 소스 라이브러리입니다.
구글 문서에도 강력 추천하고 있고, nowInAndroid 안드로이드 샘플에서도 Retrofit을 사용해 네트워크 모듈을 구현한 것을 확인할 수 있습니다. 그만큼 Android 개발 생태계에서 필수(?) 라이브러리로 자리 잡았다고 생각이 드네요.
이번 글에서는 Retrofit의 사용 방법을 간략히 알아보겠습니다.
Retrofit
https://github.com/square/retrofit
GitHub - square/retrofit: A type-safe HTTP client for Android and the JVM
A type-safe HTTP client for Android and the JVM. Contribute to square/retrofit development by creating an account on GitHub.
github.com
Retrofit는 오픈 소스라고 소개드린 것처럼 Github에 Public repository로 공개되어 있습니다. 모든 코드가 공개되어 있기 때문에 날 잡아서 코드를 분석해보고 싶지만 선뜻 시도하지 못하고 있네요. 흑흑
의존성을 추가하기 전, 지원하는 최신 버전 정보를 확인하는 것을 추천드립니다.
Retrofit 사용 방법
Retrofit의 사용 방법 설명은 nowInAndroid의 샘플 코드를 기반으로 시작하려고 합니다. 개발자 성향, 프로젝트 아키텍처에 따라서 다른 부분이 존재할 것으로 예상됩니다. 그래서 이 글도 정답은 아니며, 그저 하나의 예제로 참고해 주시면 감사하겠습니다.
직접 코드를 보실 분은 nowInAndroid 프로젝트의 core/network 모듈을 보시면 됩니다
OkHttpClient 및 Json Converter 생성
@Module
@InstallIn(SingletonComponent::class)
internal object NetworkModule {
@Provides
@Singleton
fun providesNetworkJson(): Json = Json {
ignoreUnknownKeys = true
}
...
@Provides
@Singleton
fun okHttpCallFactory(): Call.Factory = trace("NiaOkHttpClient") {
OkHttpClient.Builder()
.addInterceptor(
HttpLoggingInterceptor()
.apply {
if (BuildConfig.DEBUG) {
setLevel(HttpLoggingInterceptor.Level.BODY)
}
},
)
.build()
}
}
위 코드는 의존성 주입 라이브러리인 Hilt를 사용해서 OkhttpClient 객체와 kotlinx.serialization의 Json 객체를 생성하는 코드입니다.
간략한 Hilt 설명
우선 Hilt는 프로젝트에서 종속 항목 수동 삽입(의존성 주입)에서 객체 생성하는 상용구를 줄이는 도움을 주는 라이브러리입니다. Hilt의 라이브러리의 필요성은 이 문서에서 자세히 확인가능합니다
종속 항목이란, A 클래스에서 B 클래스가 사용된다면 B는 A의 종속 항목 클래스입니다.
Json
Retrofit은 기본적으로 Http 통신의 결과로 callable objects로 반환됩니다. 또한 요청의 body로는 ResponseBody라는 객체가 기본적으로 사용되죠.
callable objects 반환값은 콜백 형태로 값을 처리해야 한다는 점이 Kotlin과 맞지 않고, ResponseBody는 객체 생성 자체에서 오는 불편함이 있습니다.
그래서 Retrofit은 변환, 요청의 타입을 다른 타입으로 변경시켜 줄 수 있는 Converter를 제공해 주는데요. 위 코드에서 생성하는 Json이 여기에 해당됩니다. 실제로 Retrofit에 설정하는 코드는 아래에 나옵니다!
REST API 인터페이스 작성
private interface RetrofitNiaNetworkApi {
@GET(value = "topics")
suspend fun getTopics(
@Query("id") ids: List<String>?,
): NetworkResponse<List<NetworkTopic>>
@GET(value = "newsresources")
suspend fun getNewsResources(
@Query("id") ids: List<String>?,
): NetworkResponse<List<NetworkNewsResource>>
@GET(value = "changelists/topics")
suspend fun getTopicChangeList(
@Query("after") after: Int?,
): List<NetworkChangeList>
@GET(value = "changelists/newsresources")
suspend fun getNewsResourcesChangeList(
@Query("after") after: Int?,
): List<NetworkChangeList>
}
이 코드는 Retrofit을 이용해서 REST API 인터페이스를 정의한 코드입니다.
REST API를 쉽게 정의할 수 있도록 GET, POST의 어노테이션을 제공해 줍니다. annotation의 매개변수로 end point를 명시할 수 있습니다. end point는 Retrofit 객체의 Base URL에 뒤에 붙어서 네트워크 통신을 위한 요청 url을 구성합니다.
위 코드에서 나오지 않았지만 @Header처럼 Retrofit에서 지원해 주는 annotation들을 확인해 보면 더 좋을 것 같습니다.
suspend function으로 api를 정의하면, 내부적으로 IOThread에서 동작하는 Job를 생성해서 네트워크 통신을 수행하게 됩니다.
Retrofit 객체 및 API 객체 생성
@Singleton
internal class RetrofitNiaNetwork @Inject constructor(
networkJson: Json,
okhttpCallFactory: dagger.Lazy<Call.Factory>,
) : NiaNetworkDataSource {
private val networkApi = trace("RetrofitNiaNetwork") {
Retrofit.Builder()
.baseUrl(NIA_BASE_URL)
// We use callFactory lambda here with dagger.Lazy<Call.Factory>
// to prevent initializing OkHttp on the main thread.
.callFactory { okhttpCallFactory.get().newCall(it) }
.addConverterFactory(
networkJson.asConverterFactory("application/json".toMediaType()),
)
.build()
.create(RetrofitNiaNetworkApi::class.java)
}
override suspend fun getTopics(ids: List<String>?): List<NetworkTopic> =
networkApi.getTopics(ids = ids).data
override suspend fun getNewsResources(ids: List<String>?): List<NetworkNewsResource> =
networkApi.getNewsResources(ids = ids).data
override suspend fun getTopicChangeList(after: Int?): List<NetworkChangeList> =
networkApi.getTopicChangeList(after = after)
override suspend fun getNewsResourceChangeList(after: Int?): List<NetworkChangeList> =
networkApi.getNewsResourcesChangeList(after = after)
}
이번 코드의 주요 코드는 Retrofit 객체 및 API 객체 생성입니다.
봐야 할 포인트 첫 번째는 dagger.Lazy로 지연 초기화해서 Call.Factory 객체의 의존성을 주입했다는 점입니다. 저도 이번에 처음 알게 된 지식이었는데요. Hilt로 인해서 어플레이케이션 생성이 되는 시점에 싱글톤으로 선언된 의존성 객체들을 생성이 될 수 있습니다. 해당 시점은 main thread에서 동작하므로 ANR을 주의해야 합니다.
Base URL, 그리고 Json과 CallFactory를 설정해서 생성한 Retrofit 객체의 create 함수를 통해 API 객체를 생성합니다.
create 함수는 매개변수로 넘겨받은 인터페이스 타입에 대해서 GET 등의 annotation들을 처리하고, 실제로 네트워크 통신 요청하는 코드들을 생성합니다. 내부 코드가 복잡하지만 엄청 자세하고 친절하게 소개된 개발 블로그를 소개합니다.
(Android) Retrofit2는 어떻게 동작하는가 — 1. 내부 코드 분석
Retrofit2 Deep Dive #1
medium.com
'Android > Common' 카테고리의 다른 글
[Android] 음성 인식 기능 추가하는 방법 정리 (0) | 2020.03.26 |
---|---|
[Android] AAC - View Binding (0) | 2020.03.12 |
[Android] Keybard Show/Hide 감지하기 (쉬움 주의) (0) | 2020.02.12 |
[Android] RecyclerView의 최상단 최하단 감지하기 (0) | 2020.02.10 |
[Android] Settings.Panel (0) | 2019.12.13 |