본문 바로가기

Android Library

[Android Library] Retrofit (2) - retrofit in MVVM

 

안녕하세요.

 

MVVM 디자인 패턴에서 Retrofit이 어떻게 쓰이는지 실제 예시 코드와 함께 살펴보겠습니다.


Code

https://github.com/shantudas/android-architecture-components-mvvm-retrofit-kotlin

 

GitHub - shantudas/android-architecture-components-mvvm-retrofit-kotlin: This repository contains Android Architecture Component

This repository contains Android Architecture Components ( LiveData , View Model and MVVM pattern ) : work in progress - GitHub - shantudas/android-architecture-components-mvvm-retrofit-kotlin: Thi...

github.com

 

해당 깃허브에서 코드를 가져왔습니다.


Model

가져올 json 데이터에 맞게 데이터 클래스를 만들어줍니다.

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize;

@Parcelize
data class Article(
    var author: String? = null,
    var title: String? = null,
    var description: String? = null,
    var thumbnail: String? = null,
    var publishedAt: String? = null,
    var url: String? = null
) : Parcelable

서비스 인터페이스

Retrofit에게 던져줄 인터페이스를 만드는 부분입니다.

 

baseUrl 뒤에 top-headlines랑 everything 사이트에서 각각 데이터를 가져오기 위해 GET API를 적어준 모습입니다.

import retrofit2.http.GET
import retrofit2.http.Query

interface RetrofitService {

    @GET("top-headlines")
    suspend fun getHeadlines(
        @Query("country") country: String,
        @Query("apiKey") apiKey: String
    ): ArticleResponse

    @GET("everything")
    suspend fun search(
        @Query("q") query: String,
        @Query("apiKey") apiKey: String
    ): ArticleResponse
}

Repository

데이터 레이어 최상단에 위치한 Repository는 Retrofit과 통신해서 받은 데이터를 ViewModel에게 전달합니다.

class ArticleRepository_Impl(
    private val retrofitService: RetrofitService,
    private val mapper: ArticleDtoMapper

) : ArticleRepository {
    override suspend fun getArticles(country: String, token: String): List<Article> {
        return mapper.mapToDomainList(retrofitService.getHeadlines(country, token).articles)
    }
}

ViewModel

Repository에게 데이터를 가져오라고 명령을 내립니다.

 

해당 데이터는 네트워크를 사용하기 때문에 코루틴을 사용해 데이터를 가져와줍니다.

(메인 스레드를 너무 오래 잡아두면 UI를 그리는데 자원을 사용하지 못해 앱이 꺼집니다.)

import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import javax.inject.Named

@ExperimentalCoroutinesApi
class HeadlineViewModel
@ViewModelInject
constructor(
    private val repository: ArticleRepository,
    @Named("auth_token") private val token: String
) : ViewModel() {
    val articles: MutableLiveData<List<Article>> = MutableLiveData()

    init {
        viewModelScope.launch {
            val results = repository.getArticles("us", token)
            articles.value = results
        }
    }
}

Fragment

Retrofit으로 데이터를 가져왔는지 여부를 ViewModel의 변수를 통해 observe 합니다.

가져온 데이터를 어댑터를 통해 화면에 표시합니다.

@AndroidEntryPoint
class HeadlineFragment : Fragment() {
	...

    private fun setupObservers() {
        headlineViewModel.articles.observe(viewLifecycleOwner, Observer {
            if (!it.isNullOrEmpty()) adapter.setItems(ArrayList(it))
            for (item in it) {
                Log.i(TAG, "setupObservers: ${item.title}")
            }
        })
    }
}