Connect with us

Разработка

Как Blinkit решил загадку производительности Android-приложения с помощью Droid Dex

Это история о том, как Blinkit решил самую печально известную проблему Android — умную адаптацию производительности в реальном времени.

Опубликовано

/

     
     

Представьте себе: ваше приложение работает плавно на Pixel 7 Pro, но выдает ошибки ANR на Redmi Note 4. А пользователям Fold 6 приходится сталкиваться с теми же некрасивыми переходами, что и на устройстве за 6000 рублей. Звучит знакомо?

Добро пожаловать в разработку Android в 2025 году, где фрагментация устройств является одной из самых больших проблем.

Это история о том, как Blinkit решил самую печально известную проблему Android — умную адаптацию производительности в реальном времени.

Проблема: одна кодовая база, бесконечное количество устройств

Фрагментация устройств — это не просто головная боль разработчика, это ответственность бизнеса.

В Blinkit мы обслуживаем миллионы пользователей в самой разнообразной экосистеме Android в Индии, от ультрабюджетных до флагманских устройств.

Взгляните на эту ошеломляющую статистику из наших производственных данных:

  • 57% от общего числа OOM происходит на устройствах с менее чем 4 ГБ ОЗУ
  • среднее время отрисовки ключевых экранов в 2.5 раза медленнее на бюджетных телефонах по сравнению с флагманами
  • 20% пользователей прекращают работу после возникновения одной ошибки ANR

Традиционные решения? Они все не работают:

  • Консервативная ловушка: проектируйте для самого слабого устройства. Результат? Премиум-пользователи получают некачественный опыт.
  • Агрессивное заблуждение: оптимизируйте для флагманов. Результат? 60% пользователей сталкиваются с OOM и ANR.

Нам нужно было что-то лучшее — что-то более умное, что могло бы заставить приложения думать о производительности в режиме реального времени.

Представляем: Droid Dex

Представьте, что ваше приложение может определять устройство, на котором оно запущено, и мгновенно адаптироваться под него:

«Этот телефон может обрабатывать 4 одновременных видео, агрессивное кэширование и премиум-переходы» или «Этому устройству нужен режим энергосбережения, минимальное кэширование и упрощенная анимация».

Именно это и делает Droid Dex. Это не просто еще одна библиотека производительности — это интеллектуальная система классификации производительности, которая позволяет вашему приложению адаптироваться к своей рабочей среде.

// Make your app performance-aware with a single call
DroidDex.getPerformanceLevelLd(PerformanceClass.CPU)
    .observe(this) { level ->
        when (level) {
            PerformanceLevel.EXCELLENT -> enableBeastMode()
            PerformanceLevel.LOW -> activateSurvivalMode()
            else -> runBalancedMode()
        }
    }

Наука, стоящая за магией

Droid Dex постоянно отслеживает пять важнейших измерений производительности:

enum class PerformanceClass {
    CPU,        // Total RAM, Core Count, CPU Frequency
    MEMORY,     // Heap Limit, Heap Remaining, Available RAM
    NETWORK,    // Bandwidth Strength, Download Speed, Signal Strength
    STORAGE,    // Available Storage
    BATTERY     // Remaining Charge + Charging Status + Health
}

Каждое измерение классифицируется по четырем уровням производительности:

  • ОТЛИЧНЫЙ: территория флагманов премиум-класса
  • ВЫСОКИЙ: надежная производительность среднего уровня
  • СРЕДНИЙ: производительность бюджетных устройств
  • НИЗКИЙ: режим выживания

Но вот что действительно отличает Droid Dex: контекстное взвешивание.

Большинство библиотек или приложений рассматривают все измерения производительности одинаково. Это все равно, что сказать, что для фоторедактора процессор так же важен, как аккумулятор, или для офлайн-игры скорость сети так же важна, как хранилище. Это редко так работает.

Droid Dex помогает вам определить, что означает «производительность» для вашего конкретного варианта использования:

// For image-heavy e-commerce feeds
val imageLoadingProfile = DroidDex.getWeightedPerformanceLevelLd(
    PerformanceClass.NETWORK to 3.0f,    // Network is king
    PerformanceClass.MEMORY to 2.0f,     // Memory for bitmap handling
    PerformanceClass.STORAGE to 1.0f     // Storage for caching
)

// For video streaming features  
val videoStreamingProfile = DroidDex.getWeightedPerformanceLevelLd(
    PerformanceClass.CPU to 2.5f,        // Decoding power
    PerformanceClass.NETWORK to 2.0f,    // Streaming bandwidth
    PerformanceClass.BATTERY to 1.5f     // Power consumption
)

Ваше приложение становится контекстно-интеллектуальным, а не слепо универсальным.

Как Blinkit решил загадку производительности Android-приложения с помощью Droid Dex

Проверено в работе в масштабе Blinkit

Теория дешева. Данные о производстве бесценны. Вот как Droid Dex работает в реальном мире, обслуживая миллионы пользователей ежедневно.

1: Адаптивное качество изображений

Приложения для электронной коммерции критически зависят от качества изображения. Слишком высокое? Бюджетные устройства тормозят. Слишком низкое? Конверсия падает. Достижение баланса:

class ImageLoader {
    
    fun loadProductImage(imageUrl: String, imageView: ImageView) {
        val performanceLevel = DroidDex.getWeightedPerformanceLevel(
            PerformanceClass.NETWORK to 2.5f,  // Bandwidth is critical
            PerformanceClass.MEMORY to 2.0f,   // Bitmap memory pressure
            PerformanceClass.STORAGE to 1.0f   // Cache availability
        )

        val config = when (performanceLevel) {
            PerformanceLevel.EXCELLENT -> ImageConfig(
                quality = 95,
                format = "avif",
                resolution = "2048x2048",
                enableProgressiveLoading = true
            )
            PerformanceLevel.HIGH -> ImageConfig(
                quality = 85,
                format = "webp", 
                resolution = "1024x1024",
                enableProgressiveLoading = true
            )
            PerformanceLevel.AVERAGE -> ImageConfig(
                quality = 70,
                format = "jpg",
                resolution = "512x512",
                enableProgressiveLoading = false
            )
            PerformanceLevel.LOW -> ImageConfig(
                quality = 50,
                format = "jpg",
                resolution = "256x256",
                enableProgressiveLoading = false
            )
        }
        
        // Load the image using config
    }
}

2: Более умное кэширование

Кэширование ответов API — палка о двух концах. Агрессивное кэширование на устройстве с ОЗУ 2 ГБ? Мгновенная смерть. Консервативное кэширование на флагмане с 8 ГБ? Упущенные возможности. Наш подход:

class APICacheHelper {
    
    private val dynamicCacheSize: Int
        get() {
            return when(DroidDex.getPerformanceLevel(PerformanceClass.MEMORY)) {
                PerformanceLevel.EXCELLENT -> {
                    val networkLevel = DroidDex.getPerformanceLevel(PerformanceClass.NETWORK)
                    
                    if (networkLevel <= PerformanceLevel.AVERAGE) {
                        40 * 1024 * 1024  // 40MB - aggressive caching for slow networks
                    } else {
                        30 * 1024 * 1024  // 30MB - balanced approach
                    }
                }
                PerformanceLevel.HIGH -> 20 * 1024 * 1024      // 20MB
                PerformanceLevel.AVERAGE -> 10 * 1024 * 1024   // 10MB  
                PerformanceLevel.LOW -> 0                      // Disable Caching
                else -> 10 * 1024 * 1024 // fallback
            }
        }
    
    private val intelligentCache by lazy {
        object : LruCache<String, ApiResponse>(dynamicCacheSize) {
            // Actual Implementation
        }
    }
    
    fun cacheResponse(key: String, response: ApiResponse) {
        val memoryPressure = DroidDex.getPerformanceLevel(PerformanceClass.MEMORY)

        // Skip caching on critically low memory devices
        if (memoryPressure == PerformanceLevel.LOW) {
            intelligentCache.clear()
            return
        }

        intelligentCache.resize(dynamicCacheSize)
        
        // Cache the response
    }
}

3: Воспроизведение видео, знающее свои пределы

Видеоролики о продуктах повышают вовлеченность. Но проигрывать слишком много из них одновременно на бюджетном устройстве? Поприветствуйте ANR. Наш менеджер воспроизведения видео учитывает контекст:

class VideoPlaybackManager {
    
    private val maxConcurrentVideos: Int
        get() {
            val cpuLevel = DroidDex.getPerformanceLevel(PerformanceClass.CPU)
            val memoryLevel = DroidDex.getPerformanceLevel(PerformanceClass.MEMORY)
            val batteryLevel = DroidDex.getPerformanceLevel(PerformanceClass.BATTERY)
            
            return when {
                // Beast mode
                cpuLevel >= PerformanceLevel.HIGH && 
                memoryLevel >= PerformanceLevel.HIGH && 
                batteryLevel >= PerformanceLevel.AVERAGE -> 4
                
                // Balanced mode
                cpuLevel >= PerformanceLevel.AVERAGE && 
                memoryLevel >= PerformanceLevel.AVERAGE -> 2
                
                // Survival mode: One video at a time
                else -> 1
            }
        }
    
    // Real-time adaptation to changing conditions
    private fun monitorPerformanceChanges() {
        DroidDex.getPerformanceLevelLd(
            PerformanceClass.CPU, 
            PerformanceClass.MEMORY, 
            PerformanceClass.BATTERY
        ).observe(lifecycleOwner) { _ ->
            val idealVideoCount = maxConcurrentVideos
            val currentVideoCount = activeVideoPlayers.size
            
            when {
                currentVideoCount > idealVideoCount -> {
                    // Performance degraded - cleanup least important videos
                    cleanupExcessVideos(currentVideoCount - idealVideoCount)
                }
                currentVideoCount < idealVideoCount && queuedVideos.isNotEmpty() -> {
                    // Performance improved - play queued videos
                    playQueuedVideos(idealVideoCount - currentVideoCount)
                }
            }
        }
    }
}

4: Переходы, которые не убивают UX

Красивые анимации и переходы элементов из одного в другой создают первоклассный опыт. Но они также могут ухудшить производительность на недорогих устройствах. Наше решение адаптивно:

class AnimationManager {
    
    data class AnimationProfile(
        val enableSharedTransitions: Boolean,
        val animationDuration: Long,
        val enableParallaxEffects: Boolean
    )
    
    private val animationProfile: AnimationProfile
        get() {
            val cpuLevel = DroidDex.getPerformanceLevel(PerformanceClass.CPU)
            val memoryLevel = DroidDex.getPerformanceLevel(PerformanceClass.MEMORY)
            val batteryLevel = DroidDex.getPerformanceLevel(PerformanceClass.BATTERY)

            return when {
                // Premium experience for capable devices
                cpuLevel >= PerformanceLevel.HIGH && 
                memoryLevel >= PerformanceLevel.HIGH && 
                batteryLevel >= PerformanceLevel.AVERAGE -> {
                    AnimationProfile(
                        enableSharedTransitions = true,
                        animationDuration = 350L,
                        enableParallaxEffects = true
                    )
                }

                // Balanced experience  
                cpuLevel >= PerformanceLevel.AVERAGE && 
                memoryLevel >= PerformanceLevel.AVERAGE -> {
                    AnimationProfile(
                        enableSharedTransitions = true,
                        animationDuration = 250L,
                        enableParallaxEffects = false
                    )
                }

                // Simplified experience for budget devices
                else -> {
                    AnimationProfile(
                        enableSharedTransitions = false,
                        animationDuration = 150L,
                        enableParallaxEffects = false
                    )
                }
            }
        }

    // Use the animationProfile to perform actual transitions & animations
}

Почему каждому разработчику Android нужен Droid Dex

Без:

  • Универсальная производительность, которая не подходит никому
  • Разочарованные пользователи и потери для бизнеса
  • Неиспользование потенциала флагманских устройств
  • Более высокий показатель сбоев и ANR

С ним:

  • Интеллектуальная адаптация производительности
  • Более счастливые пользователи во всех сегментах
  • Максимальный потенциал на каждом устройстве
  • Значительно меньше сбоев и ANR

Хватит разрабатывать для среднего. Начните разрабатывать для всех. Сделайте приложение адаптивным. Сделайте его умным.

Усильте свое приложение с помощью Droid Dex.

Примечание: Droid Dex — это проект с открытым исходным кодом, который активно поддерживается командой инженеров Blinkit. Мы призываем вас делиться своими отзывами, примерами использования и вклаом.

Если вы нашли это полезным, рассмотрите возможность поставить репозиторию GitHub ⭐️ — это поможет другим узнать о проекте. Поздоровайтесь на LinkedIn или подпишитесь на меня на GitHub.

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: