Skip to content

Commit

Permalink
[#17] 통신을 위한 네트워크 관련 베이스 코드 작성
Browse files Browse the repository at this point in the history
- 레트로핏 CallAdapter 적용
  • Loading branch information
heechokim committed Apr 4, 2022
1 parent ba29bf4 commit 54d7cd5
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 212 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.moyerun.moyeorun_android">

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

<application
android:name=".MoyeoRunApplication"
android:allowBackup="true"
Expand Down
30 changes: 3 additions & 27 deletions app/src/main/java/com/moyerun/moyeorun_android/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ package com.moyerun.moyeorun_android
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.moyerun.moyeorun_android.common.Lg
import com.moyerun.moyeorun_android.network.ApiErrorCode
import com.moyerun.moyeorun_android.network.callAdapter.NetworkResult
import com.moyerun.moyeorun_android.network.calladapter.ApiResponse
import com.moyerun.moyeorun_android.network.client.apiService
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
Expand All @@ -21,35 +20,12 @@ class MainActivity : AppCompatActivity() {
GlobalScope.launch {
val response1 = apiService.getUserRepoList("choheeis")
when (response1) {
is NetworkResult.Success -> {
is ApiResponse.Success -> {
Lg.d("getUserRepoList Success") }
is NetworkResult.Failure -> {
is ApiResponse.Failure -> {
// 비즈니스 로직 상의 에러
// 이넘 클래스로 별도 관리하는 에러 코드와 비교하여 알맞은 로직 작성
val errorCode = response1.code // 이건 상태코드이긴 한데, error 안에 코드 넣어서 보내주는 것 사용.
if (errorCode == ApiErrorCode.NOT_EXIST_USER.code) {
// 에러 대응
}
Lg.d("getUserRepoList ApiError")
}
is NetworkResult.NetworkError -> {
// 네트워크 에러와 언논 에러는 전처리되면 좋을 듯
// Success랑 API Error만 뷰 모델에서 관리하도록.
Lg.d("getUserRepoList NetworkError")
}
is NetworkResult.UnknownError -> { Lg.d("getUserRepoList UnknownError") }
}

val response2 = apiService.getAppName()
when (response2) {
is NetworkResult.Success -> { Lg.d("getAppName Success") }
is NetworkResult.Failure -> {
// 비즈니스 로직 상의 에러
// 이넘 클래스로 별도 관리하는 에러 코드와 비교하여 알맞은 로직 작성
Lg.d("getAppName ApiError")
}
is NetworkResult.NetworkError -> { Lg.d("getAppName NetworkError") }
is NetworkResult.UnknownError -> { Lg.d("getAppName UnknownError") }
}
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,4 @@ package com.moyerun.moyeorun_android.network
data class Success<T>(
val message: String,
val data: T
)

data class Failure<T>(
val message: String,
val error: T
)
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
package com.moyerun.moyeorun_android.network.api

import com.moyerun.moyeorun_android.network.Failure
import com.moyerun.moyeorun_android.network.Success
import com.moyerun.moyeorun_android.network.callAdapter.NetworkResult
import com.moyerun.moyeorun_android.network.calladapter.ApiResponse
import retrofit2.http.GET
import retrofit2.http.Path

interface ApiService {
@GET("users/{user}/repos")
suspend fun getUserRepoList(@Path("user") user: String): NetworkResult<Success<Any>, Failure<Any>>

@GET("appName")
suspend fun getAppName(): NetworkResult<Success<Any>, Failure<Any>>
suspend fun getUserRepoList(@Path("user") user: String): ApiResponse<Success<Any>>
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.moyerun.moyeorun_android.network.calladapter

/**
* Success : API 호출 성공 시, 데이터를 Wrapping 합니다.
* Failure : API 호출 실패 시, 에러를 Wrapping 합니다.
*/
sealed class ApiResponse<out T> {
data class Success<T>(val data: T) : ApiResponse<T>()
data class Failure(val error: Throwable) : ApiResponse<Nothing>()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.moyerun.moyeorun_android.network.calladapter

import okhttp3.Request
import okio.Timeout
import retrofit2.*
import java.lang.UnsupportedOperationException

internal class ApiResponseCall<T : Any>(
private val delegate: Call<T>
) : Call<ApiResponse<T>> {

override fun enqueue(callback: Callback<ApiResponse<T>>) {
delegate.enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()

if (body != null) {
callback.onResponse(
this@ApiResponseCall,
Response.success(ApiResponse.Success(body))
)
} else {
val invocation = call.request().tag(Invocation::class.java)
val method = invocation?.method()
val message = if (method != null) {
"Response from " +
method.declaringClass.name +
'.' +
method.name +
" was null but response body type was declared as non-null"
} else {
"No tag is attached with Invocation::class.java. So, invocation can't find."
}
val e = KotlinNullPointerException(message)

callback.onResponse(
this@ApiResponseCall,
Response.success(ApiResponse.Failure(e))
)
}
} else {
callback.onResponse(
this@ApiResponseCall,
Response.success(ApiResponse.Failure(HttpException(response)))
)
}
}

override fun onFailure(call: Call<T>, t: Throwable) {
callback.onResponse(
this@ApiResponseCall,
Response.success(ApiResponse.Failure(t))
)
}
})
}

override fun clone(): Call<ApiResponse<T>> = ApiResponseCall(delegate.clone())

override fun execute(): Response<ApiResponse<T>> {
throw UnsupportedOperationException("ApiResponseCall doesn't support execute")
}

override fun isExecuted(): Boolean = delegate.isExecuted

override fun cancel() {
delegate.cancel()
}

override fun isCanceled(): Boolean = delegate.isCanceled

override fun request(): Request = delegate.request()

override fun timeout(): Timeout = delegate.timeout()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.moyerun.moyeorun_android.network.calladapter

import retrofit2.Call
import retrofit2.CallAdapter
import java.lang.reflect.Type

class ApiResponseCallAdapter<T: Any>(
private val returnType: Type
) : CallAdapter<T, Call<ApiResponse<T>>> {

override fun responseType(): Type = returnType

override fun adapt(call: Call<T>): Call<ApiResponse<T>> = ApiResponseCall(call)
}
Loading

0 comments on commit 54d7cd5

Please sign in to comment.