Flutter лагает на дешёвом Android: 10 правок для списков, старта и памяти
Flutter-приложение тормозит в основном по вине кода: лишние перерисовки, тяжёлые вычисления в главном потоке, неуменьшенные картинки и утечки памяти. Замерьте кадры в profile-режиме на самом слабом телефоне парка, уберите эти причины, и лаги на списках, на старте и к концу смены обычно уходят без переписывания на натив.
📦 Демо прошло отлично, а на складе приложение замирает
Приложение для кладовщиков сдают заказчику на демо. Список остатков листается плавно, сканер откликается мгновенно. Через неделю на складе картина другая: кладовщик сканирует штрихкод, экран замирает, кладовщик жмёт ещё раз, и в 1С уходят два одинаковых движения. Список номенклатуры дёргается при прокрутке. К концу смены телефон горячий, а приложение вылетает.
Склад тут ни при чём. Демо шло на флагмане разработчика, по быстрому Wi-Fi и с горсткой тестовых позиций. Работает же приложение на недорогом Android трёхлетней давности, по слабой сети, с полным каталогом. Код не менялся, но условия поменялись, поэтому все скрытые перерасходы вылезли сразу.
Ставка понятная. Кладовщики возвращаются к бумажным накладным и Excel, потому что бумага не зависает. Машина стоит под разгрузкой, пока приёмку пересканируют. Дубли в учёте приходится разгребать вручную, а деньги на разработку не окупаются: приложением никто не пользуется, значит, и данных из него нет. Дешевле разобраться с производительностью до релиза, чем через полгода объяснять руководителю склада, почему «оно глючит».
🔍 «Flutter медленный, нужен натив»: разбор заблуждения
После такого провала первым звучит вывод: Flutter медленная технология, надо было писать нативно. Обычно это неверно. Flutter рисует интерфейс собственным движком и в релизной сборке компилируется в машинный код. Тормозит то, что в него положили: перерисовка всего экрана на каждый тап, разбор большого ответа сервера в главном потоке, фотографии в полном размере.
Первая рекомендация из десяти касается замеров, потому что без них правки идут вслепую. Debug-сборка тормозит всегда: в ней включены проверки и JIT-компиляция, её цифры ничего не значат. Запускайте приложение командой flutter run --profile на реальном телефоне, причём на самом слабом из тех, что стоят у сотрудников. Откройте DevTools, вкладку Performance. Бюджет кадра при 60 Гц около 16 мс, всё, что дольше, пользователь видит как рывок.
Дальше смотрите, какой поток перегружен. Долгие кадры в UI-потоке говорят, что виноват Dart-код: тяжёлый build или вычисления. Долгие кадры в raster-потоке говорят, что отрисовка слишком дорогая: эффекты, слои, крупные картинки. Это разводит по разным разделам ниже и не даёт чинить не то. Если оба потока укладываются в бюджет, а тормозит всё равно, ищите причину в обмене с сервером и 1С, это рекомендация 10.
🎞 Прокрутка и рывки интерфейса: рекомендации 2–5
- ✓Ставьте const перед виджетами, которые не меняются, и режьте длинные build-методы на мелкие виджеты. Flutter пропускает пересборку неизменного const-поддерева целиком. Экран, собранный в одном огромном build, пересобирается весь при любом изменении, а разделённый на виджеты пересобирает только нужный кусок.
- ✓Держите состояние ближе к месту, где оно нужно. setState на корневом экране перерисовывает всё дерево под ним. Вынесите изменяемую часть в отдельный виджет или подписывайтесь на кусок состояния: select в Riverpod и Provider, BlocSelector в Bloc. Счётчик корзины не должен заставлять перерисовываться каталог.
- ✓Для длинных списков берите ListView.builder или SliverList, а не ListView с готовым массивом children: builder создаёт только видимые строки. Если строки одной высоты, задайте itemExtent, и Flutter перестанет считать размеры на лету. Каталог грузите страницами, а не целиком.
- ✓Осторожно с Opacity, ClipRRect, BackdropFilter и большими тенями: они заставляют движок отрисовывать отдельный слой (saveLayer), и на слабом GPU это первое, что даёт рывки в raster-потоке. Замените Opacity на цвет с альфа-каналом, ClipRRect на borderRadius в декорации контейнера. Анимируемые элементы оберните в RepaintBoundary, чтобы их перерисовка не тянула соседей.
⚙️ Старт и главный поток: рекомендации 6–8
Правило простое: всё, что занимает больше одного кадра, в главном изоляте делать нельзя.
- ✓Уводите тяжёлую работу из главного изолята: разбор большого JSON, сортировку и фильтрацию каталога делайте через compute или Isolate.run. Если выгрузка номенклатуры из 1С разбирается в главном потоке, экран замирает на время разбора, и кладовщик снова жмёт кнопку.
- ✓Уменьшайте картинки. Фото товара с камеры весит мегабайты, а для превью хватает пары сотен пикселей. Просите у сервера миниатюры, передавайте cacheWidth и cacheHeight в Image.network, кэшируйте на диск через cached_network_image. Без этого декодирование полноразмерных фото съедает и память, и кадры.
- ✓Разгрузите main(). Не запускайте до runApp аналитику, push-SDK и открытие всех баз подряд: каждая строка перед первым экраном оттягивает старт. Покажите первый экран, остальное инициализируйте следом. Заодно пройдитесь по pubspec и уберите пакеты, которыми давно никто не пользуется.
🔋 Память и обмен с сервером: рекомендации 9–10
- ✓Закрывайте то, что открыли. В dispose освобождайте контроллеры, FocusNode и таймеры, отменяйте StreamSubscription. Забытая подписка держит в памяти целый экран, а симптом виден к концу смены: утром приложение работало, после долгой работы вылетает. Вкладка Memory в DevTools покажет объекты, которые растут от экрана к экрану.
- ✓Разберитесь с обменом. Часто тормозит не Flutter, а запрос: приложение каждый раз просит у 1С весь каталог. Переходите на дельта-обмен, то есть отдавайте только изменения с прошлой синхронизации, храните данные в локальной базе на телефоне (Drift, sqflite) и показывайте их сразу, а обновление тяните фоном. Сделайте операции идемпотентными: повторный запрос с тем же идентификатором не создаёт второй документ, и двойной тап кладовщика не порождает дубль. Так строится интеграция мобильного приложения с 1С у нас: экран открывается из локальной базы и не ждёт ответа сервера.
⚖️ Если правок мало: четыре пути и когда какой выбирать
Бывает, что после всех десяти пунктов приложение всё равно не тянет. Тогда выбор такой.
| Путь | Что делаем | Срок и риск | Когда оправдан |
|---|---|---|---|
| Точечная оптимизация Flutter | Замеры, правки по списку из статьи, релиз обновления | Самый короткий срок, приложение продолжает работать | Приложение уже в эксплуатации, тормозят конкретные экраны |
| Нативные модули для отдельных экранов | Тяжёлый экран или работу с железом пишем на Kotlin или Swift и подключаем к Flutter | Дольше, часть кода живёт в двух версиях: под Android и под iOS | Упираетесь в возможности устройства: драйвер сканера, камера, тяжёлая графика |
| Полный переход на натив | Две отдельные кодовые базы | Самый долгий и дорогой. Если причина была в вашем коде, лаги переедут вместе с ним | Редко: очень тяжёлая графика или требования платформы, которые Flutter не закрывает |
| Переписать на Flutter заново | Новая архитектура, перенос экранов | Срок близок к новой разработке | Всё состояние лежит в одном классе, экраны не делятся на виджеты, правка в одном месте ломает соседнее |
Есть ещё вариант, о котором забывают. Если приложение нужно только для внутреннего учёта и опирается на формы 1С, хватит 1С:Мобильной платформы. Дизайн и анимации там ограничены, зато не нужна отдельная команда мобильных разработчиков, а обмен с базой строится средствами самой платформы.
💼 Что делаем мы и сколько это стоит
Мы проектируем приложения так, чтобы сценарий со складом не повторился. Сборку проверяем на самых слабых телефонах парка клиента, а не на флагманах разработчиков. Обмен с 1С строим на дельтах и локальной базе, операции делаем идемпотентными.
Разработка мобильного приложения у нас стартует от 500 000 руб. Итог зависит от числа экранов, платформ и глубины обмена с 1С: склад со сканером и приложение для торговых агентов считаются по-разному. Точную цену называем после разбора задачи. Если приложение уже есть и тормозит, пришлите сборку и описание сценария: снимем профиль на слабом устройстве и скажем, что из десяти пунктов даст эффект, а что нет.
Для торговых агентов и клиентов, которые заказывают с телефона, те же правила заложены в B2B-приложение с 1С: каталог и цены лежат на устройстве, заказ уходит в базу без ожидания, статус подтягивается фоном.
❓ Частые вопросы
Почему Flutter-приложение тормозит, хотя фреймворк считается быстрым?
Скорость Flutter упирается в код приложения. Чаще всего виноваты перерисовка всего экрана на каждое действие, разбор большого ответа сервера в главном потоке, картинки в полном размере и незакрытые подписки. На флагмане это незаметно, на недорогом Android с полным каталогом лаги видны сразу. Начните с замеров в profile-режиме на самом слабом телефоне.
Как проверить производительность Flutter-приложения?
Соберите приложение командой flutter run --profile и запустите на реальном слабом телефоне, а не на эмуляторе. Откройте DevTools, вкладку Performance: там видны кадры дольше 16 мс и то, какой поток перегружен, UI или raster. Вкладка Memory покажет утечки. Замеры в debug-режиме недостоверны, он всегда медленнее релиза.
Когда Flutter-приложение стоит переписывать на натив?
Редко. Оправдано, если вы упираетесь в возможности устройства, например в драйвер терминала сбора данных, или в очень тяжёлую графику. Если тормозят списки, старт и обмен с сервером, причина в коде, и после переписывания те же ошибки переедут в новую кодовую базу. Сначала замеры и точечные правки, потом решение.
Сколько стоит разработка мобильного приложения с обменом с 1С?
Разработка мобильного приложения у нас стартует от 500 000 руб. Итог зависит от числа экранов, платформ и глубины обмена с 1С: склад со сканером и приложение для торговых агентов считаются по-разному. Точную цену называем после разбора задачи, чтобы вы не платили за лишнее.
Как ускорить обмен мобильного приложения с 1С?
Не запрашивайте весь каталог при каждом открытии. Отдавайте только изменения с прошлой синхронизации, храните данные в локальной базе на телефоне и показывайте их сразу, а обновление тяните фоном. Тяжёлый разбор ответа выносите в отдельный изолят, а операции делайте идемпотентными, чтобы повторный запрос не создавал дубль документа.
Или позвоните: +7 906 045-28-27 — в рабочее время с 9:00 до 19:00
Остались вопросы? Нужна помощь?
Менеджеры компании с радостью ответят на ваши вопросы, произведут расчет стоимости услуг и подготовят индивидуальное коммерческое предложение.
Бесплатная консультация

