Этап 1: единый OkHttpClient (переиспользование пула/кэша) — ч.1
CI / verify (push) Has been cancelled
CI / release (push) Has been cancelled

Раньше NetworkFactory создавал новый OkHttpClient на КАЖДЫЙ запрос (~32 места):
TLS-handshake + новый пул/диспатчер на запрос + утечка ExecutorService.
Теперь: один базовый клиент (общий ConnectionPool/Dispatcher + диск-кэш 20МБ),
авторизованные варианты через base.newBuilder() (шарят пул/кэш), кэшируются по
кредам+таймаутам. Публичный API НЕ менялся — 32 вызова не тронуты.
Init диск-кэша в F7MobileApp.onCreate.

+3 unit-теста (переиспользование клиента, общий пул). 401→interceptor НЕ делал
(меняет семантику исключений — отдельный шаг).

Проверено: 15 тестов зелёные + assembleRelease BUILD SUCCESSFUL, APK 53 МБ.
This commit is contained in:
b-dev-mobile
2026-07-07 23:14:20 +00:00
parent d9cacb8c9c
commit c45ebd8d49
4 changed files with 70 additions and 7 deletions
@@ -1,9 +1,37 @@
package ru.forbion.f7cloud.core.network
import android.content.Context
import okhttp3.Cache
import okhttp3.OkHttpClient
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
/**
* Фабрика HTTP-клиентов. Раньше создавала НОВЫЙ OkHttpClient на КАЖДЫЙ запрос (~32 места) →
* TLS-handshake и новый пул/диспатчер на запрос, утечка ExecutorService. Теперь:
* - один базовый клиент (общий ConnectionPool + Dispatcher + диск-кэш);
* - авторизованные варианты — через `base.newBuilder()` (шарят пул/диспатчер/кэш);
* - экземпляры кэшируются по кредам+таймаутам → переиспользуются, соединения живут.
*
* Публичный API НЕ менялся — все вызывающие (`newAuthedClient*`) работают как прежде.
* NB: 401→UnauthorizedException пока проверяется в репозиториях вручную; централизация
* через interceptor — отдельный шаг (меняет семантику исключений).
*/
object NetworkFactory {
@Volatile
private var base: OkHttpClient = OkHttpClient()
private val clients = ConcurrentHashMap<String, OkHttpClient>()
/** Вызывать один раз из Application.onCreate — добавляет диск-кэш (нужен cacheDir). */
fun init(context: Context) {
val cacheDir = File(context.applicationContext.cacheDir, "http-cache")
base = OkHttpClient.Builder()
.cache(Cache(cacheDir, 20L * 1024 * 1024)) // 20 МБ
.build()
clients.clear() // пересобрать производные клиенты уже с кэшем
}
fun newAuthedClient(
username: String,
appPassword: String,
@@ -11,13 +39,16 @@ object NetworkFactory {
callTimeoutSeconds: Long = 30,
readTimeoutSeconds: Long = 30,
): OkHttpClient {
return OkHttpClient.Builder()
.callTimeout(callTimeoutSeconds, TimeUnit.SECONDS)
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(readTimeoutSeconds, TimeUnit.SECONDS)
.applyUnsafeSslIfNeeded(trustAllCerts)
.addInterceptor(BasicAuthInterceptor(username, appPassword))
.build()
val key = "$username|$appPassword|$trustAllCerts|$callTimeoutSeconds|$readTimeoutSeconds"
return clients.getOrPut(key) {
base.newBuilder() // общий пул/диспатчер/кэш базового клиента
.callTimeout(callTimeoutSeconds, TimeUnit.SECONDS)
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(readTimeoutSeconds, TimeUnit.SECONDS)
.applyUnsafeSslIfNeeded(trustAllCerts)
.addInterceptor(BasicAuthInterceptor(username, appPassword))
.build()
}
}
/** Collabora / richdocuments: cold start and WOPI can be slow on mobile networks. */