Динамические ссылки с Koin и Retrofit - PullRequest
2 голосов
/ 12 октября 2019

Использование Retrofit для сетевых вызовов и Koin для внедрения зависимостей в приложении Android, как поддерживать динамическое изменение URL?

(при использовании приложения пользователи могут переключаться на другой сервер)

РЕДАКТИРОВАТЬ: сетевой модуль объявлен так:

fun networkModule(baseUrl: String) = module {

    single<Api> {

        Retrofit.Builder()
                .baseUrl(baseUrl) 
                .client(OkHttpClient.Builder().readTimeout(30, TimeUnit.SECONDS)
                        .connectTimeout(30, TimeUnit.SECONDS)
                        .writeTimeout(30, TimeUnit.SECONDS)
                        .build())
                .build().create(Api::class.java)
    }

Я запускаю Koin в AplicationКласс onCreate, как это:

 startKoin {

        if (BuildConfig.DEBUG) AndroidLogger() else EmptyLogger()

        androidContext(this@App)

        modules(listOf(networkModule(TEST_API_BASE_URL), storageModule, integrationsModule, appModule))
    }

Ответы [ 2 ]

0 голосов
/ 23 октября 2019

Я пытался с модулями загрузки / выгрузки Koin ... и в течение короткого периода времени это работало, но позже, после минимального изменения, я не смог заставить его перезагрузить снова.

ВВ конце концов, я решил это с помощью объекта-оболочки:

class DynamicRetrofit(private val gson: Gson) {

private fun buildClient() = OkHttpClient.Builder()
        .build()

private var baseUrl = "https://etc..." //default url

private fun buildApi() = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(buildClient())
        .build().create(MyApi::class.java)

var api: MyApi = buildApi()
    private set

fun setUrl(url: String) {
    if (baseUrl != url)
        baseUrl = url

    api = buildApi()
}}

Я объявляю это внутри модуля Koin следующим образом:

  single<DynamicRetrofit>()
    {
        DynamicRetrofit(get(), get())
    }

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

dynamicRetrofit.api.makeSomeRequest()

Это было хорошее решение для моего случая, так как я очень редко меняю baseUrl. Если вам нужно делать частые и параллельные звонки на два разных сервера, это, вероятно, будет неэффективно, так как вы часто воссоздаете HTTP-клиент.

0 голосов
/ 23 октября 2019

Я недавно столкнулся с той же проблемой. Наиболее удобный способ - использовать Interceptor для динамического изменения baseUrl.

class HostSelectionInterceptor(defaultHost: String? = null, defaultPort: Int? = null) : Interceptor {
    @Volatile var host: String? = null
    @Volatile var port: Int? = null

    init {
        host = defaultHost
        port = defaultPort
    }

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
        var request = chain.request()

        this.host?.let {host->
            val urlBuilder = request.url().newBuilder()

            urlBuilder.host(host)

            this.port?.let {
                urlBuilder.port(it)
            }
            request = request.newBuilder().url(urlBuilder.build()).build()
        }

        return chain.proceed(request)
    }
}

Инициализировать его с помощью URL-адреса по умолчанию.

single { HostSelectionInterceptor(HttpUrl.parse(AppModuleProperties.baseUrl)?.host()) }
single { createOkHttpClient(interceptors = listOf(get<HostSelectionInterceptor>()))}

И добавить этот перехватчик при создании OkHttpClient.

val builder = OkHttpClient().newBuilder()    
interceptors?.forEach { builder.addInterceptor(it) }

Чтобы изменить URL, вам нужно только обновить элемент-перехватчик.

fun baseUrlChanged(baseUrl: String) {
    val hostSelectionInterceptor = get<HostSelectionInterceptor>()
    hostSelectionInterceptor.host = baseUrl
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...