Study Record

[안드로이드] Retrofit 살펴보기 (ViewModel, Moshi, coroutines) 본문

안드로이드

[안드로이드] Retrofit 살펴보기 (ViewModel, Moshi, coroutines)

초코초코초코 2023. 8. 9. 14:54
728x90

 

Retrofit 은 Android 에서 네트워크를 이용해 서버(Backend)와 데이터를 교환하는 것을 도와주는 라이브러리이다.

 

앱에서 서버에 데이터 요청(혹은 다른 서버와 관련된 작업)하면 Retrofit2 라이브러리가 서버와 통신하여 받을 데이터가 있으면 받아온다. 서버에서 받은 데이터를 Converter 라이브러리가 클라이언트 프로젝트에서 사용할 수 있는 데이터 형식으로 바꿔준다.

 

서버에서 응답으로 보내는 데이터는 주로 XML 혹은 JSON 으로 돌려준다. 데이터 형식을 바꿔주는 Converter 라이브러리로 Moshi 는 서버에서 받은 JSON 형식(데이터 형식)으로 받은 데이터를 Kotlin 객체로 변환하는 Android JSON Parser 이다.

 

+ Converter 라이브러리로 Scalar 가 있는데 이 라이브러리는 서버에서 받은 데이터를 String 형식으로 변환해 준다.

 

 

 

😶 Retrofit2, Moshi Dependencies 추가하기

build.gradle(Projects) 단위에 다음 레포지토리를 추가한다.

repositories {
   google() 
   mavenCentral()
}

 

build.gradle(Module) 단위에 Retrofit2, Moshi Dependencies 를 추가한다.

dependencies {
    // Retrofit
    implementation "com.squareup.retrofit2:retrofit:2.9.0"
    // Moshi
    implementation 'com.squareup.moshi:moshi-kotlin:1.13.0'
    // Retrofit with Moshi Converter
    implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'

}

 

 

 

😶 테스트용 웹 REST API 서버

무료로 시험해 볼 수 있는 사이트이다.

 

https://jsonplaceholder.typicode.com/

 

JSONPlaceholder - Free Fake REST API

{JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. Serving ~2 billion requests each month.

jsonplaceholder.typicode.com

 

 

안드로이드에서 Internet 권한이 있어야 네트워크를 사용할 수 있다. AndroidManifest.xml 에 인터넷 권한을 추가해 준다.

<manifest ...>
    ...
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

 

 

 

😶 Retrofir2 사용하기

제일 먼저 서버와 통신하는 Retrofit 인스턴스를 생성한다. 생성할 때 converter 도 같이 명시해줘야 하는데 converter 로는 moshi converter 로 한다. 기본 baseUrl 메서드에는 통신할 서버 기본 주소를 적는다.

private const val BASE_URL =
    "https://jsonplaceholder.typicode.com/"

private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

// Retrofit 인스턴스
private val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .baseUrl(BASE_URL)
    .build()

 

서버 통신을 시험해 볼 URL 은 https://jsonplaceholder.typicode.com/todos 이며 응답은 다음과 같은 형식으로 온다.

[
  {
    "userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "quis ut nam facilis et officia qui",
    "completed": false
  },
...
]

 

서버에서 오는 데이터 형식에 맞춰 데이터 클래스를 만든다. @Json 어노테이션으로 서버에서 받은 데이터 형식 이름과 실제로 앱 프로젝트에서 사용하는 변수 이름이 다를 때 사용할 수 있다.

import com.squareup.moshi.Json

data class TodoData(
    val userId: Int,
    val id: Int,
    val title: String,
    @Json(name = "completed") val checked: Boolean
)

 

 

TodoApiService 만든다. 여기에는 서버에 통신할 함수를 만든다. 함수의 리턴값은 서버에서 받은 응답에 대한 데이터 형식이다. 위에서 본 테스트 데이터가 List 형식으로 왔으니 List<TodoData> 로 받아준다. HTTP 통신 메서드가 GET 이고 요청 주소는 기본 서버 주소 + todos 이므로 @GET("todos") 어노테이션을 명시해 준다.

interface TodoApiService {
    @GET("todos")
    suspend fun getTodos(): List<TodoData>
}

object TodoApi {
    val retrofitService : TodoApiService by lazy { 
        retrofit.create(TodoApiService::class.java)
    }
}

 

서버와의 통신 작업은 오래 걸리는 작업이기 때문에 메인 스레드에서 실행하면 안 된다. 따라서 스레드를 만들어야 하는데 ViewModel 에서는 viewModelScope 라는 ViewModel 에 묶여 있는 CoroutineScope 를 제공한다. ViewModel 이 메모리에서 지워지면(종료되면) 자동으로 해당 viewModelScope 와 관련된 스레드가 취소된다.

class TodoViewModel : ViewModel() {
    private val _todoData = MutableLiveData<List<TodoData>>()
    val todoData : LiveData<List<TodoData>>
        get() = _todoData

    init {
        getTodoData()
    }

    private fun getTodoData() {
        viewModelScope.launch {
            try {
                // 서버 통신
                _todoData.value = TodoApi.retrofitService.getTodos()
            } catch (e: Exception) {
                _todoData.value = listOf()
            }
        }
    }
}

 

 

 

 

728x90