개발을 하다보면 아래의 상황에서 Local Json File을 사용하게 됩니다.
일반적으로 Android 프로젝트는 Retrofit이라는 통신 라이브러리를 사용합니다.
Retrofit을 이용하게 되면, Gson처럼 자동으로 파싱을 하기때문에 편리하나, 로컬 json 파일을 읽는 기능은 따로 존재하지 않습니다.
물론 Local에서 Test를 할경우 mockWebServer Library
를 이용하여 통신을 조작하긴 합니다만, 테스트 용도에서 사용하라고 권장하고 있습니다.
그래서 단순히 파일을 read하고 Gson으로 파싱하자니, 테스트하기위한 불필요한 코드가 추가되어서 불편합니다.
어떻게 Retrofit으로 Json 파일을 읽을수 있을까요?
답은 Interceptor에 있습니다.
Retrofit은 내부적으로 OkHttp 통신 라이브러리를 사용합니다.
Application에서 Request를 던져주면 Okhttp으로 통신하고 결과값을 가져옵니다.
이때 우리는 Application에 돌아오는 값을 Interceptor
를 통해 조작할 수 있습니다.
Interceptor
는 과연 어떤일까지 가능할까요?
Interceptor
는 공통 헤더를 장착할때 많이 사용됩니다.val newRequest = chain.request().newBuilder()
.addHeader("token", NaverToken).build()
예를 들어, 어떤페이지로 접근하려면 토큰을 헤더에 붙여야하는데 Interceptor
를 이용하여, 쉽게 대응이 가능하죠.
chain.proceed
를 이용하여 서버로 통신 값을 받아올수 있습니다.val response = chain.proceed(newRequest)
감이 좀 오셨나요? Interceptor
로 request를 가로챈뒤 proceed를 사용하지않으면 해결되는 문제입니다!
방향을 잡았으면 코드짜야겠죠.
런타임때 json 파일을 불러와야하기때문에 Asset폴더에 파일을 넣어둡시다.
왜 그런지 이유는 Android-Asset-vs-Row-vs-Resource에서 참고하세요.
class MockRequestInterceptor(private val context: Context) : Interceptor {
companion object {
private val JSON_MEDIA_TYPE = "application/json".toMediaTypeOrNull()
private const val MOCK = "mock"
}
override fun intercept(chain: Interceptor.Chain): Response {
val filename = request.url.pathSegments.last()
return Response.Builder()
.request(request)
.protocol(Protocol.HTTP_1_1)
.message("")
.code(200)
.body(context.readFileFromAssets("api-response/$filename.json").toResponseBody(JSON_MEDIA_TYPE))
.build()
통신이 발생하면 Interceptor가 Application 통신을 가로채게됩니다.
proceed()가 발생하지 않았기 때문에 실제로 네트워크 통신은 일어나지 않았고,
Response를 따로 생성하여 Json값을 Body로 넣었습니다.
해당 로직을 통해 API의 EndPoint들이 네트워크가 아닌 로컬에서 발생 됩니다!
Retrofit의 데이터 흐름을 가져와봤습니다.
나머지는 자세히 볼필요 없고 아래에 색깔을 칠한것을 보시면됩니다.
Converter와 OKHttp가
RequestBody와 ResponseBody를 통해 직접 전달되는것을 확인할 수 있습니다.
(이 사진에서는 MoshiConverter라고 적혀있지만, GsonConverter가 될수도, Scala가 될수도 있습니다.)
그렇다면 Interceptor
는 어디에 위치하게 될까요?
Interceptor
는 이쪽부근에 위치하여, 통신을 가로챌수 있으며, ResponseBody를 조작할 수 있습니다.
읽어주셔서 감사합니다.
안드로이드 오픈톡방 화이팅 <3