ENAN

Developer, Artist, Traveler

공부/Android

Coroutine과 Retrofit 함께 활용하기 -2) 레트로핏 편

ENAN 2020. 6. 13. 18:04

* 이 글에서는 coroutine과 함께 retrofit을 활용하기 위해 필요한 내용만을 다룹니다.

retrofit에 대해 공부할 방대한 내용들은 여러 좋은 글들에서 설명되어 있으니 여기서는 최소한만 설명하고 넘어갑니다. *



* coroutine을 함께 사용하는 방법으로 설명하니까 코루틴이나 다른 비동기 처리 방법을 잘 모른다면 미리 읽고 오기

2020/06/03 - [공부/기록] - Coroutine과 Retrofit 함께 활용하기 -1) 코루틴 편

 

Coroutine과 Retrofit 함께 활용하기 -1) 코루틴 편

* 이 글에서는 retrofit을 coroutine과 함께 활용하기 위해 필요한 내용만을 다룹니다. coroutine에 대해 공부할 방대한 내용들은 여러 좋은 글들에서 설명되어 있으니 여기서는 최소한만 설명하고 넘어

enant.tistory.com

레트로핏이란?

쉽게 말해서, '서버와 통신을 하기 위해 사용하는 라이브러리'다. 서버와 통신을 한다는 것은, 서버에 요청을 보내고 응답을 받으면서 데이터를 주고 받는 과정을 얘기한다. 레트로핏은 그 복잡한 과정을 쉽게 처리할 수 있도록 도와주는 녀석이다. 아니 안쉬운데?

 

왜 쉽다고 말하는지는 레트로핏 없이 서버와 통신하는 서비스를 구현해보면 알게 될 것이다. 다른 방법들은 우선 접하기도 어렵고, 작성해야 하는 코드도 더럽고, 매번 반복적으로 connection 설정, input/outputstream 할당을 해야 하거나, 성능상 느리다는 이슈가 있는 AsyncTask 를 사용하거나 뭐 여러가지 불편하고 비효율적인 점이 많다.

 

아무튼 레트로핏은 안드로이드에서 REST API를 편하게 호출하기 위해 가장 많이 사용하는 라이브러리 라고 할 수 있다. 

 

레트로핏 사용

1. 의존성 추가

2. 오브젝트 만들기

3. API Interface 만들기

  3-1. api에 맞는 data class 만들기

4. 호출

 

 

1. 의존성 추가

//$retrofitVersion 에 최신 버전 넣기
    implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
    implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion"

retrofit과 gsonConverter도 같이 추가해준다. 

gson Converter가 뭔가요 ? ⬇️

더보기

gson converter는 json으로 받아온 요청을 미리 정의된 클래스에 자동으로 넣어주는 편한 녀석이다!

예를 들면,

{
    "id":123,
    "name":"enan",
    "playlist":
    	[
          {"artist":"ruel","title":"PainKiller"},
          {"artist":"HONNE","title":"No song without you"},
          {"artist":"Jeremy Zucker","title":"Comethru"}
        ]
}

라는 형식으로 JSON 데이터가 서버에서 날아오면, 우리는 

data class User(
    val id:Int,
    val name:String,
    val playlist:ArrayList<Song>
)

data class Song(
    val artist:String,
    val title:String
)

이런식으로 응답 받을 데이터클래스를 정의해두면 gsonconverter가 알아서 이 클래스에 데이터를 넣어준다! 

 

2. 오브젝트 만들기

 - 오브젝트 클래스는 기본적으로 2개의 함수로 구성되어 있다.

      - 1) getRetrofit()

          - 기본적인 레트로핏 클래스를 만들어주는 역할. 빌더 패턴으로 create된 레트로핏 클래스를 반환함

          - 빌더 create 과정

                 - baseUrl : api server url을 넣는다.

                 - addConverterFactory : 필요한 converter를 넣는다. 여기에서는 Gson converter를 넣었다.

 

      - 2) getApiService()

          - getRetrofit 함수로 빌드된 레트로핏 객체를 생성하고, api interface를 연결해주는 역할이다.

             실제로 통신이 필요한 곳에서 호출하는 함수!

 

* 뼈대

- RetrofitObject.kt

object RetrofitObject {

    private fun getRetrofit():Retrofit{
        val baseUrl ="https://yourapiserver.com/"

        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    fun getApiService(): ApiService {
        return getRetrofit().create(ApiService::class.java)
    }
}

 

3. API service 인터페이스 만들기

   - 사용되는 api들을 모아놓은 인터페이스다. 앞으로 api는 여기에다 추가하면 된다.

   - @annotation = 통신 메서드(GET, POST, PUT 등)

   - ()안에 api 주소 지정 ( baseUrl 다음 부분만 적으면 됨)

   - suspend fun : coroutine scope 안에서 사용하기 위해 suspend function으로 선언 (* coroutine 안쓸거면 그냥 fun으로 선언)

   - request body가 필요 없으면 함수 인자도 적을 필요 없고, 필요하면 @Body request : 요청 클래스* 형태로 사용하면 된다.

         * 컨버터가 요청 클래스를 자동으로 JSON형태로 변환시켜 요청한다!

   - Response<응답 클래스> : JSON 형태로 온 응답이 응답 클래스로 변환되어 반환된다.

 

- ApiService.kt 뼈대

 interface ApiService {

    @POST("api1주소/")
    suspend fun fetchSomeData(
    ): Response<SomeData>

    @POST("api2주소/")
    suspend fun fetchSomething(
        @Body request: FetchSomethingRequest
    ): Response<FetchSomethingResponse>
}

 

4. 필요한 곳에서 호출하기

    - 네트워크 통신은 무조건 비동기적으로 일어나야 한다. 동기적으로 네트워크 통신을 요청하면 바로 오류 발생! 여기서는 코루틴을 사용해서 비동기 통신을 수행한다.

        - 코루틴스코프 안에 요청하는 구문을 작성 (launch{} 안에)

        - 요청 구문 : 응답클래스를 저장할 변수 = NetworkUtil.getApiService().호출할api함수( 요청클래스 데이터 ) 

        - 응답 클래스에 대해 원하는 작업 수행

- 예시

launch{ 
    val someDataResponse = NetworkUtil.getApiService().fetchSomeData() 
    someDataList.postValue(someDataResponse.body())
}
launch{ 
    val someDataResponse = NetworkUtil.getApiService().fetchSomeData(
    	FetchSomethingRequest(
        	someParameter1,
            someParameter2,
            someParameter3...
        )
    ) 
    someDataList.postValue(someDataResponse.body())
}

5. 더 활용하기

더보기

   - 1) OKHttpClient
OKHttpClient 객체를 만들고 retrofit build 과정에 .client(OkHttpClient객체)와 같이 client 객체를 넣어주는 방식으로 사용 가능하다. Client 객체도 빌더 패턴으로 만들 수 있으며, Timeout 등을 지정할 수도 있고, 헤더에 어떤 값을 추가하고 싶을 때(ex. auth인증) 필요한 Intercepter를 추가할 수 있다.

이를 활용하면 데이터 연결이 끊길 때도 처리할 수 있다. NoConnectionInterCepter class 를 만들고clientBuilder.addIntercepter(NoConnectionIntercepter(context))와 같은 식으로 client 객체에 intercepter를 추가해주는 방식이다. 이렇게만 말하면 무슨 소리를 하는 건지 이해할 수 없을 텐데 다음에 따로 설명하는 글을 적을 예정이다! 적으면 링크를 붙일 것!

 

    - 2) error Handling
ResponseHelper 클래스를 작성해서 요청을 wrapping해 사용하면 예상치 못한 통신 오류가 발생했을 때 앱이 종료되는 불상사를 Handling할 수 있다. 이 역시 다음에 자세히 설명할 것!