⭐️ 기존 방식

Modeling Retrofit Responses With Sealed Classes and Coroutines

  1. MainViewModel
@HiltViewModel
class MainViewModel @Inject constructor(
	private val userInfoRepository: UserInfoRepository
) {

	fun getUserData() {
			viewModelScope.launch(Dispatchers.IO) {
					mainRepository.getUserData().collect { result ->
                when (result) {
                    is NetworkResult.Success -> {
												hideProgress()
										}
										is NetworkResult.Error -> {
												hideProgress()
										}
										is NetworkResult.Error -> {
												showProgress()
										}
								}
					}
			}
	}

	fun getProfileData() {
			viewModelScope.launch(Dispatchers.IO) {
					mainRepository.getProfile().collect { result ->
                when (result) {
                    is NetworkResult.Success -> {
												hideProgress()
										}
										is NetworkResult.Error -> {
												hideProgress()
										}
										is NetworkResult.Error -> {
												showProgress()
										}
								}
					}
			}
	}

}
  1. UserInfoRepository
class UserInfoRepository @Inject constructor(
    private val userApiService: UserApiService
) : Repository {
		fun getUserData() = flow {
				emit(NetworkResult.Loading)
        emit(safeApiCall{ userApiService.getUserData() })
		}

		fun getProfileData() = flow {
				emit(NetworkResult.Loading)
        emit(safeApiCall{ userApiService.getProfileData() })
		}
}
  1. NetworkResult
sealed class NetworkResult<T : Any> {
    data class Success<T: Any>(val data: T) : NetworkResult<T>()
    data class Error<T: Any>(val code: Int, val message: String?) : NetworkResult<T>()
    object Loading : NetworkResult<Nothing>()
}

suspend fun <T> safeApiCall (
    execute: suspend () -> Response<T>
): NetworkResult<T> {
    return try {
        val response = execute()
        val body = response.body()
        if (response.isSuccessful && body != null) {
            return NetworkResult.Success(body)
        } else {
            return NetworkResult.Error(code = response.code(), message = response.message())
        }
    } catch (e: HttpException) {
        return NetworkResult.Error(code = e.code(), message = e.message())
    } catch (e: Throwable) {
        return NetworkResult.Error(null, e.message ?: e.toString())
    }
}

👩🏻‍💻 구조 설명

  1. MainViewModel에서 Dispatcher.IO를 사용하여 api를 호출한다.
  2. UserRepository에서 safeApiCall 함수를 통해 NetworkResult 형태의 api 리턴값을 리턴한다.

🤔 생각해볼점

  1. Dispatcher.IO를 하드코딩 하고있다. Coroutine Dispacher & Hilt
  2. UserRepository에서 api마다 Loading을 먼저 호출해주고있다.