코루틴과 레프로핏을 이용해서 MVVM 패턴을 만들고
네트워크를 통해 데이터를 가져와서(데이터 엔드포인트)
리사이클러 뷰를 통해서 보여준다.
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()
}
}