본문 바로가기

Project/Lifehelper

Branch : 02_WeatherApiSetting_callback (Retrofit2, gson, OkHttp, OkHttp Interceptor)

728x90

commit message : Establish communication with API by callback method using okhttp, okhttp interceptor, retrofit2

 

 

경로 : app/build.gradle

 //okhttp and okhttp interceotor
    def okhttp_version = "4.9.0"
    implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
    implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"

    //retrofit2
    def retrofit_version = "2.9.0"
    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"

 

 

경로 : app/src/main/java/com/example/lifehelper/DomainLayer/repository/Retrofit_Service.kt

interface Retrofit_Service {

    @GET(API.SEARCH_WEATHER)
    fun search_weather(
            @Query("lat") lat : String,
            @Query("lon") lon : String) : Call<JsonElement>

} 

 

 

경로 : app/src/main/java/com/example/lifehelper/DataLayer/Client/RetrofitClient.kt

object RetrofitClient {

    fun getApiClient(baseUrl: String) : Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(baseUrl)
            // 위에서 설정한 client로 retrofit client를 설정한다.
            .client(getOkHttpClient())
            .build()
    }

    fun getOkHttpClient() : OkHttpClient {
        Log.d(Constants.TAG, "${this@RetrofitClient::class.java.simpleName}" +
                "getOkHttpClient() called")

        val client = OkHttpClient.Builder()

        val baseParmsInterceptor = object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                Log.d(Constants.TAG, "${this@RetrofitClient::class.java.simpleName}" +
                        "intercept() / chain : $chain")

                /**
                 * 1) 공통 파라미터 장착
                 */
                val originalRequest = chain.request()

                val addClientIdUrl = originalRequest .url.newBuilder()
                    .addQueryParameter("appid", API.API_ID)
                    .addQueryParameter("lang", API.LANGUAGE)
                    .build()

                Log.d(Constants.TAG, "${this@RetrofitClient::class.java.simpleName}" +
                        "intercept() / addClicentUrl : $addClientIdUrl")

                val finalRequest = originalRequest.newBuilder()
                    .url(addClientIdUrl)
                    .method(originalRequest.method, originalRequest.body)
                    .build()

                /**
                 * 2) 서버로 부터 응답받기
                 */
                val response = chain.proceed(finalRequest) //오리지날 요청으로 변경하면 401에러 문제없이 출력됨

               /*
                if(response.code != 200){
                    Handler(Looper.getMainLooper()).post {
                        //Handler() - android.os, 백그라운드 스레드에서 작업 중, ui 스레드에서 실행하도록 변경
                        //Toast.makeText(App.instance, "${response.code} 에러 입니다.", Toast.LENGTH_SHORT).show()
                    }
                }
               */
                return response
            }
        }

        client.addInterceptor(baseParmsInterceptor)
        // 위에서 생성한 기본 파라미터 인터셉터를 okhttp clent에 추가

        return client.build()
    }

} 

2) 서버로 부터 응답을 받고 HTTP 상태 코드에 따라 처리를 할 수 있지만, UI 조작은 다른 곳에서 처리하는게 좋을 것 같아 일단은 주석 처리

 

 

경로 : app/src/main/java/com/example/lifehelper/DomainLayer/usecase/RetrofitManager.kt

class RetrofitManager {
    companion object {
        val instance = RetrofitManager()
    }

    private val retrofitService: Retrofit_Service? =
            RetrofitClient.getApiClient(API.BASE_URL).create(Retrofit_Service::class.java)

    fun searchWeather(lat: String?, lon: String?, completion: (RESPONSE_STATE, JsonElement?) -> Unit) {
        Log.d(Constants.TAG, "${this::class.simpleName} " +
                "searchWeater() called")

        val lat = lat.let { it } ?: ""
        val lon = lon.let { it } ?: ""

        retrofitService?.search_weather(lat, lon)?.clone()?.enqueue(object : retrofit2.Callback<JsonElement> {
            override fun onResponse(call: Call<JsonElement>, response: Response<JsonElement>) {
                Log.d(Constants.TAG, "${this@RetrofitManager::class.simpleName} " +
                        "onResponse() called : response.raw(): ${response.raw()}")
                Log.d(Constants.TAG, "${this@RetrofitManager::class.simpleName} " +
                        "onResponse() called : response.body(): ${response.body()}")
                Log.d(Constants.TAG, "${this@RetrofitManager::class.simpleName} " +
                        "onResponse() called : response.code(): ${response.code()}")

				var weatherData: WeatherData? = null
                
                when (response.code()) {
                    200 -> {
                    
                    	response.body?.apply {
                        val body = this.asJsonObject
                        val weather = body.getAsJsonArray("weather")

                        weather.forEach { weatherItem ->
                            val weatherObject = weatherItem.asJsonObject
                            val main = weatherObject.get("main").asString

                            Log.d(Constants.TAG, "${this@WeatherViewModel::class.java.simpleName} " +
                                        "main : $main")

                            	weatherData = weatherData(
                                	main = main
                            	)
                        	}
                        }
                        weatherData?.let { completion(RESPONSE_STATE.OK, it) }
                    }
                }
            }

            override fun onFailure(call: Call<JsonElement>, t: Throwable) {
                Log.d(Constants.TAG, "${this@RetrofitManager::class.java.simpleName} " +
                        "onFailure() called : ${t}")

                completion(RESPONSE_STATE.FAIL, null)
            }

        })
    }
}

 

 

 

경로 : app/src/main/java/com/example/lifehelper/DomainLayer/model/WeatherData.kt

data class WeatherData(
    var main : String?
    //var description : String?,
    //var wind_speed : String?,
    //var cloud : String?,
    //var rain_1h : String?,
    //var snow_1h : String?
) 

응답을 받은 후 파싱한 결과가 제대로 출력되는지만 확인하기 위해서 main만 사용한 상태 

 

 

경로 : app/src/main/java/com/example/lifehelper/PresentationLayer/Fragment/WeatherFragment.kt

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        RetrofitManager.instance.searchWeather("37.5683", "126.9778") {
            responseState, weatherData ->

            when(responseState){
                RESPONSE_STATE.OK -> {
                    Log.d(Constants.TAG, "HomeActivity api 호출 성공 ")
                }
                RESPONSE_STATE.FAIL -> {
                    Log.d(Constants.TAG, "HomeActivity api 호출 실패")
                }
                RESPONSE_STATE.NONE -> {
                    Log.d(Constants.TAG, "HomeActivity api 결과 없음 ")
                }
            }
        }
    }
}