perf(android): ленивый плеер записей, O(n) merge каталога, @Immutable, лог только в debug
- RecordingPlaybackController: ExoPlayer создаётся лениво (на первый play) и освобождается в stop() — раньше второй плеер висел в памяти всю сессию у каждого. Поллер позиции 500мс крутится только во время игры (был вечный 2 Гц main-loop). - StationRepositoryImpl.refreshStations: merge каталога O(n) через apiById/apiByName индексы вместо .find на каждую станцию (было O(n²) ~700×700 на холодном старте). Убраны verbose Log.d-трейсы (оставлен Log.e/.w на ошибки). - Track/Station/StreamQuality помечены @Immutable — read-only модели, иначе списки tags/qualities делали класс нестабильным → лишние рекомпозиции списков. - HttpLoggingInterceptor только при BuildConfig.DEBUG (включён buildConfig feature): в релизе нет оверхеда на каждый запрос и утечки URL в logcat.
This commit is contained in:
@@ -38,13 +38,11 @@ class StationRepositoryImpl @Inject constructor(
|
||||
}
|
||||
|
||||
override suspend fun refreshStations(): Result<Unit> = withContext(Dispatchers.IO) {
|
||||
android.util.Log.d("StationRepo", "refreshStations() called")
|
||||
// Тяжёлый парс stations.json (~700) + сетевые вызовы + запись в Room —
|
||||
// на IO, а не на главном потоке (был риск jank/ANR при холодном старте).
|
||||
try {
|
||||
// 1. Load local stations from assets
|
||||
val localStations = localDataSource.loadStations()
|
||||
android.util.Log.d("StationRepo", "Loaded ${localStations.size} local stations")
|
||||
val localGroups = localDataSource.loadGroups()
|
||||
|
||||
// 2. Try to enrich with Record API data (covers, streams, tags)
|
||||
@@ -56,14 +54,16 @@ class StationRepositoryImpl @Inject constructor(
|
||||
// Локальные id (1,2,3…) не совпадают с id Record-каталога, и в ассетах
|
||||
// нет prefix — поэтому сопоставляем сначала по id, затем по названию
|
||||
// (стабильный общий ключ), иначе обложки/потоки не подтягиваются.
|
||||
// Индексы строим один раз (было O(n²): .find по ~700 на каждую из ~700).
|
||||
// asReversed+associateBy сохраняет ПЕРВЫЙ по имени (как делал .find).
|
||||
val apiById = apiStations.associateBy { it.id }
|
||||
val apiByName = apiStations.asReversed()
|
||||
.associateBy { it.name.trim().lowercase() }
|
||||
val merged = localStations.map { local ->
|
||||
// Обложки/потоки из Record API — только для станций сети Radio Record.
|
||||
// Иначе чужим сетям (DFM, HitFM и т.д.) цеплялись бы обложки Record.
|
||||
val apiStation = if (local.source == "record") {
|
||||
apiStations.find { it.id == local.id }
|
||||
?: apiStations.find {
|
||||
it.name.trim().equals(local.name.trim(), ignoreCase = true)
|
||||
}
|
||||
apiById[local.id] ?: apiByName[local.name.trim().lowercase()]
|
||||
} else null
|
||||
if (apiStation != null) {
|
||||
val domain = apiStation.toDomain()
|
||||
@@ -83,7 +83,6 @@ class StationRepositoryImpl @Inject constructor(
|
||||
// 4. Save to DB. Сохраняем текущие отметки «избранное», иначе REPLACE
|
||||
// в insertAll затрёт их при каждом пересоздании каталога (на старте).
|
||||
val favoriteIds = db.stationDao().getFavoriteIdsOnce().toSet()
|
||||
android.util.Log.d("StationRepo", "Saving ${merged.size} merged stations to DB (избранных сохранено: ${favoriteIds.size})")
|
||||
val entities = merged.mapIndexed { index, station ->
|
||||
StationEntity(
|
||||
id = station.id,
|
||||
@@ -100,7 +99,6 @@ class StationRepositoryImpl @Inject constructor(
|
||||
)
|
||||
}
|
||||
db.stationDao().insertAll(entities)
|
||||
android.util.Log.d("StationRepo", "Inserted ${entities.size} stations into DB")
|
||||
|
||||
// 4b. Скрываем станции, которые бэкенд пометил оффлайн (мёртвые потоки).
|
||||
// Если бэкенд недоступен — оставляем как есть (фолбэк на статичный enabled).
|
||||
@@ -108,7 +106,6 @@ class StationRepositoryImpl @Inject constructor(
|
||||
val offlineIds = radiolaApi.getOfflineStationIds()
|
||||
if (offlineIds.isNotEmpty()) {
|
||||
db.stationDao().deleteByIds(offlineIds)
|
||||
android.util.Log.d("StationRepo", "Скрыто оффлайн-станций: ${offlineIds.size}")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.w("StationRepo", "Не удалось получить offline-id: ${e.message}")
|
||||
|
||||
Reference in New Issue
Block a user