Ошибка при повторном использовании клиента Retrofit при обращении к api разных сайтов

Рейтинг: 0Ответов: 1Опубликовано: 12.06.2023

Пишу небольшое своё приложение. В нём есть необходимость получения данных с сервера из-за чего обращаюсь к API разных сайтов. Есть 3 разных сайта, к api которых я обращаюсь. По отдельности каждый из запросов работает корректно, данные доходят успешно.

Но если обратиться сначала к API по первому URL, а потом по второму, то будет ошибка. При запросе ко второму сайту используется URL первого сайта. И как-то я не могу прийти к тому, как это устранить, ведь в getClient() подставляю каждый раз разный URL в объекте Common.

Буду очень благодарен за любую помощь и советы.

Клиент Retrofit:

object RetrofitClient {
    private var retrofit: Retrofit? = null

    fun getClient(baseUrl: String) : Retrofit {

        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY

        val client = OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .build()

        if (retrofit == null) {
            retrofit = Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return retrofit!!
    }
}

Объект Common:

object Common {
    private val BASE_URL = "https://dummyjson.com/"
    private val BASE_WEATHER_URL = "https://api.open-meteo.com/"
    private val BASE_SIGHTS_URL = "https://api.opentripmap.com/"
    val retrofitServiceAuth: MainApi
        get() = RetrofitClient.getClient(BASE_URL).create(MainApi::class.java)

    val retrofitServiceWeather: MainApi
        get() = RetrofitClient.getClient(BASE_WEATHER_URL).create(MainApi::class.java)

    val retrofitServiceSights: MainApi
        get() = RetrofitClient.getClient(BASE_SIGHTS_URL).create(MainApi::class.java)
}

Интерфейс MainApi:

interface MainApi {
    @POST("auth/login")
    suspend fun authFun(@Body authRequest: AuthRequest): Response<User>

    @GET("v1/forecast?latitude=52.52&longitude=13.41&current_weather=true")
    suspend fun getWeather(): Response<WeatherModel>

    @GET("0.1/ru/places/radius?radius=20000&lon=37.617070&lat=55.751693&rate=3&format=geojson&limit=300")
    suspend fun getSights(@Query("apikey") apiKey: String): Response<SightsModel>
}

Сами запросы вызываю в разных функциях для каждого запроса так (для примера):

suspend fun retrofitWeatherRequest(): String {
    var temperature = ""

    withContext(Dispatchers.IO) {
        val response = Common.retrofitServiceWeather.getWeather()
        temperature = response.body()?.current_weather?.temperature.toString()
    }
    return temperature
}

Ответы

▲ 1

Вы создаете объект retrofit лишь один раз. При повторном вызове getClient() возвращется ранее созданный объект, так как у вас там есть проверка retrofit == null.

Один из возможных способов решения проблемы, убрать состояние внутри object RetrofitClient:

object RetrofitClient {
    fun createClient(baseUrl: String) : Retrofit {
        ...
        return Retrofit.Builder()
            ...
            .build()
    }
}

При этом, чтобы не создавать ретрофит при каждом запросе, создавайте его в object Common один раз (без использования get()):

object Common {
    val retrofitServiceAuth: MainApi =
        createClient(BASE_URL).create(MainApi::class.java)
    val retrofitServiceWeather: MainApi =
        createClient(BASE_WEATHER_URL).create(MainApi::class.java)
    val retrofitServiceSights: MainApi =
        createClient(BASE_SIGHTS_URL).create(MainApi::class.java)
}

Если вам нужна отложенная инициализация, используйте делегирование by lazy.

Кроме этого, если запросы, отправляемые на разные сервера, — разные, то будет лучше, если вы разделите интерфейс MainApi на три разных интерфейса.