안드로이드 retrofit2, moshi, 코루틴을 이용한 비동기 rest api 호출하기

개발환경

안드로이드 스튜디오 4.1.1
JDK 1.8
모든 코드는 github에 있습니다.


프로젝트 생성

Empty Activity 선택






Language를 Kotlin으로 선택
Minimum SDK API21 선택 후 Finish 클릭



의존성 추가


//retrofit2
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
implementation 'com.squareup.retrofit2:converter-moshi:2.7.1'

def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

com.squareup.retrofit2:retrofit는 retrofit2를 사용하기 위한 라이브러리
com.squareup.retrofit2:converter-moshi는 json 문자열을 data class로 자동변환 해주기 위한 라이브러리
androidx.lifecycle:lifecycle-runtime-ktx 코루틴을 사용하기 위한 라이브러리


data class 작성

https://jsonplaceholder.typicode.com/todos/1 리턴되는 json을 object로 컨버팅 합니다.
해당 url을 요청해 보면

{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}

위와 같은 구조의 데이터를 response 해줍니다.
각각의 propery에 대응하는 data class를 생성합니다.


data class Todo(
var userId: Int,
var id: Int,
var title: String,
var completed: Boolean
)



Endpoint class 작성


  interface TodoService {
@GET("/todos/{userId}")
fun get(@Path("userId") userId: Int) : Call<Todo>

companion object {
const val BASE_URL = "https://jsonplaceholder.typicode.com"
}
}

@Path는 endpoint의 {userId}를 파라메터 값으로 변환시켜 줄 때 사용합니다.
BASE_URL는 변하는 않는 host이므로 companion object로 정의합니다.

MainActivity


class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val retrofit = Retrofit.Builder()
.baseUrl(TodoService.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create())
.build();

val todoService = retrofit.create(TodoService::class.java)
todoService.get(1).enqueue(object: Callback<Todo> {
override fun onFailure(call: Call<Todo>?, t: Throwable?) {
Log.v("retrofit", "call failed")
}

override fun onResponse(call: Call<Todo>?, response: Response<Todo>?) {
                val todo: Todo? = response?.body()
textView.text = todo.toString()
}
})
}
}

  • Retrofit 인스턴스를 생성합니다.
  • Retrofit 인스턴스를 통해 endpoint가 정의된 TodoService를 생성합니다.
  • enqueue 메소드는 비동기로 처리됩니다.
  • 전송 될 데이터가 response?.body()에 Todo로 컨버팅 됩니다.


비동기 request를 코루틴으로 처리하기


interface TodoService {
@GET("/todos/{userId}")
fun get(@Path("userId") userId: Int) : Call<Todo>

@GET("/todos/{userId}")
suspend fun getSuspend(@Path("userId") userId: Int) : Todo

companion object {
const val BASE_URL = "https://jsonplaceholder.typicode.com"
}
}

getSuspend 메소드를 정의합니다. suspend 키워드가 필요하며 Call 삭제 합니다.



class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val retrofit = Retrofit.Builder()
.baseUrl(TodoService.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create())
.build();

val todoService = retrofit.create(TodoService::class.java)

CoroutineScope(Dispatchers.Main).launch {
val todo = todoService.getSuspend(1);
textView2.text = todo.toString()
}
}
}

suspend 메소드는 CoroutineScope(Dispatchers.Main).launch 블럭 안에서 실행시켜야 합니다. 코루틴을 사용하게 되면 비동기 처리를 동기 처리와 같은 느낌으로 코딩이 가능하게 되며 코드가 간결해 집니다.


댓글

댓글 쓰기