Как стать автором
Обновить

Комментарии 11

Тихий ужас у вас в коде. Почему
val answer1 = restClient.buildRequest<Answer1> {
            

возвращает Answer?, логично чтобы buildRequest возвращал Request, не?
} catch (e: Exception) {
viewState.showError(e.message.toString())
} catch (e: InterruptedException) {
viewState.showError(e.message.toString())
}

Второй catch никогда не сработает
Согласен, исправил
} catch (e: Exception) {
throw Exception(e.message ?: «Ошибка запроса»)
} catch (t: Throwable) {
throw Exception(t.message ?: «Ошибка запроса»)
}

Почему бы не сделать проще:
} catch (t: Throwable) {
throw Exception(t.message ?: «Ошибка запроса»)
}
Такая кажущаяся общей функция на самом деле нифига не общая и не решает никаких задач. вы также туда передаете api::request1 и api::request2 и параметры к ним, просто в очень непонятном и причудливом виде.
Надо просто сделать класс TokenApi, который будет вызывать эти же функции но добавлять токен
class TokenApi(private val api: Api, private val prefs: SharedPreferences) {

    suspend fun request1(last: Long, autoView: Boolean): Answer1 {
        val res = api.request1(last, autoView, headers())
        saveToken(res)
        return res?.body()
    }

    suspend fun request2(id: Long): Answer2 {
        val res =  api.request2(id, headers())
        saveToken(res)
        return res?.body()
    }
    private val TOKEN_KEY = "Token"
    private val ID_KEY = "ID"
    fun headers(): Map<String, String> {
        return mapOf(
            TOKEN_KEY to prefs.getString(Constants.Preferences.SP_TOKEN_KEY, ""),
            ID_KEY to prefs.getLong(Constants.Preferences.SP_ID, -1).toString()
        )
    }

    fun saveToken(res) {
        val newToken = res?.headers()?.get(TOKEN_KEY)
        val newID = res?.headers()?.get(ID_KEY)?.toLong()
        if (newToken.notNull() && newID.notNull()) {
            prefs.edit()
                .putString(TOKEN_KEY, newToken)
                .putLong(ID_KEY, newID)
                .apply()
        }
    }
}

...


try {
    val tApi = new TokenApi(api, prefs)
    val answer1 = tApi.request1(1, false)
    val answer2 = tApi.request2(1234)
} catch (e: Exception) {
       viewState.showError(e.message.toString())
} catch (e: InterruptedException) {
        viewState.showError(e.message.toString())
} finally {
        viewState.hideProgress()
}

Вот и все, проще и понятнее чем мудреж с дженериками

catch нужно поменять местами

Я бы вообще второй catch убрал. Я про общую идею, исключения я просто скопировал. Там и с корутинами лажа вообщем-то
Да, так изначально и было. Но в каждой функции класса TokenApi вы делаете одно и тоже. В чём отличие функции request1 от request2? Только в самом запросе. Так почему бы не передавать запрос в параметре, а не делать для всех запросов обёртки?
Так и в варианте с жденериками куча повторов, например
fieldHashMap = restClient.fiedsMapForRequest2(1234)
                headersHashMap = restClient.headers()

Но это не главное, главное что в buildRequest передается функция которую надо вызвать, и список параметров которые надо передать. Это просто непонятный сложный вызов функции.
Если бы buildRequest возвращал Request и не выполнял его сразу, а например куда-то складывал для последующего выполнения — это имело бы смысл. Но для простого вызова функции так усложнять незачем, по-моему.
А почему бы просто не задействовать interceptors, и не городить кучу лишнего кода в presenter-слое?
Тоже так подумал. Единственный минус interceptors для такого функционала в том, что там нужно реализовать синхронизацию в 2х или 3х местах, чтобы не пустить запросы из параллельных потоков до конца процессов установки/обновления токенов. При этом еще не получить deadlock.
Так что в целом interceptors- более правильный вариант, но требует больших знаний о многопоточности
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории