Coroutine 과 Retrofit

probehub·2021년 12월 11일

android coroutine

목록 보기
3/7

목표

  • 코루틴과 레프로핏을 이용해서 MVVM 패턴을 만들고

  • 네트워크를 통해 데이터를 가져와서(데이터 엔드포인트)

  • 리사이클러 뷰를 통해서 보여준다.

템플릿 코드 url

  • ToDo 현재 viewModel 코드는 dummyData 로 채워진 상태이다. 이 부분을 Retrofit2 를 이용하도록 바꿔야한다.

개인적으로 생각하는 포인트

viewModel 에 livedata 를 적용하였다. 리사이클러뷰에 들어가는 데이터가 업데이트 될 경우 어댑터의 데이터를 갱신하도록 하였다. 이때도 notifyDataSetChanged() 등의 함수를 호출해서 리사이클러뷰에 변화를 줘야한다.

해결

레트로핏 구현

interface APIInterface {
    @GET("DevTides/countries/master/countriesV2.json")
    suspend fun getCountries() : Response<List<Country>>
}
object CountriesService {

    private val BASE_URL = "https://raw.githubusercontent.com"

    fun getCountryService() : APIInterface {
        return Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(APIInterface::class.java)
    }
}

CountriesService 클래스의 getCountryService() 함수를 호출하면 레트로핏 인터페이스를 호출하게 된다. 그리고 모델 클래스도 변화가 필요하다.

data class Country(
    @SerializedName("name")
    val countryName: String?,

    @SerializedName("capital")
    val capital: String?,

    @SerializedName("flagPNG")
    val flag: String?
)

뷰 모델 코드 수정

뷰 모델의 fetchCountries() 함수가 레트로핏을 이용해서 데이터를 가져오는 식으로 바뀌어야 한다.

class ListViewModel: ViewModel() {
    val countriesService = CountriesService.getCountryService()
    var job: Job? = null
    val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
        onError("Exception: ${throwable.localizedMessage}")
    }

    val countries = MutableLiveData<List<Country>>()
    val countryLoadError = MutableLiveData<String?>()
    val loading = MutableLiveData<Boolean>()

    fun refresh() {
        fetchCountries()
    }

    private fun fetchCountries() {
        loading.value = true
        job = CoroutineScope(Dispatchers.IO + exceptionHandler).launch {
            val response = countriesService.getCountries()
            withContext(Dispatchers.Main) {
                if (response.isSuccessful) {
                    countries.value = response.body()
                    countryLoadError.value = null
                    loading.value = false
                } else {
                    onError("Error : ${response.message()}")
                }
            }
        }
    }


    private fun onError(message: String) {
        countryLoadError.value = message
        loading.value = false
    }

    override fun onCleared() {
        super.onCleared()
        job?.cancel()
    }
}
profile
개발자

0개의 댓글