3. В основном будет преобразование во flutter что бы показать то, что вышло - что выйдет меньше чем писать свои костыли
Как итог: если добавлять более 1 шага обработки изображения, то приходим к коду как отдельный пакет image
P.S. Не говорю, что не нужно пробовать делать что-то своё, просто, иногда получается слишком много не нужного кода (например, как в статье где использовался шейдер, который родился из незнания API рисования)
У Matrix4 есть уже реализованные методы для разных преобразований - почему бы не использовать их?
У Image нужно вызывать dispose, иначе она будет вечно в памяти
Минус вашего подхода - потеря оригинала изображение (в следствии рисования его на канвасе) - что ведёт к ситуации, когда вырезанный фрагмент в вашем приложении не такой же, как если бы я вырезал его инструментом, предназначенным для этого
Я заметил, что качество при отрисовке картинок в CustomPainter может сильно теряться, они как бы становятся пиксельными. Заметно, когда переводишь обычную красивую картинку, например, из ассетов в ui.Image и рисуешь в пейнтере
В коде нету преобразования байтов обратно в модели, а используются геттеры - это добавляет некоторый оверхед на постоянную десериализацию + компилятор не может знать, что геттеры всегда возвращают одни и те же значения
Можно ли написать DI библиотеку так, что бы она в debug резолвила зависимости в рантайме (как scout) , а в release во время компиляции (как dagger)?
Это решит проблему долгих сборок для разработчиков и в тоже время конечные пользователи не будут затронуты, так как каждый пользователь не будет платить за удобство разработчика
Сам враппер пишется на Objective-C, но его можно использовать внутри Swift. Например, у меня на скриншоте с кодом на Swift в 56 строке используется tryBlock из Objective-C. А сам код Objective-C со Stack Overflow. Поэтому, мы можем писать врапперы для Objective-C в Objective-C и потом использовать в Swift
Это достаточно обычная проблема, когда в Swift используется что-то из Objective-C. Если какой-то Objective-C код падает в рантайме, то можно обернуть его в другой Objective-C код, который это отловит. Тыц
Я так понимаю, что от Modifier.drawWithCache нету смысла, так как происходит постоянное изменение времени, а значит, что шейдеры пересоздаются на каждую перерисовку
В целом в корне дерева создаётся контейнер с помощью ProviderScope или если нужно, то создаётся ранее и потом вставляется в корень дерева с помощью UncontrolledProviderScope
Так же, обычно провайдеры создают как top-level variables, что бы они не пересоздавались.
Так же достаточно удобная возможность - использование riverpod как DI:
final httpQueryProvider = Provider(
(ref) => HttpQuery(
ref.watch(dioProvider),
),
dependencies: [
dioProvider,
],
name: 'httpQuery',
);
class HttpQuery {
HttpQuery(this._dio);
final Dio _dio;
Future<Object?> get({
required String url,
Map<String, Object?>? queryParameters,
Map<String, Object?>? headerData,
}) {
...
}
}
Кстати, я пересмотрел статью ещё раз и не понял как связан LocaleNotifier и HttpQuery
Как я понял, в большинстве случаев, Intellij Idea не виновата, так как они просто подключаются к Dart Analysis Server. Порой кажется, что в команде Dart не хотят что-либо улучшать. Не хочу никого оправдывать, но выходит, что IDE виновата только от части и это не отменяет проблем описанных в статье. Я бы, например, очень хотел бы, что бы локальные переменные или функции имели приоритет в выдаче, но мечтать не вредно. тыц
Логично встает вопрос: если стандартные компоненты приходится переписывать для кастомизации под конкретные проекты, то зачем Material и Cupertino виджеты гвоздями прибиты к Flutter SDK? Не логичнее ли было вынести их как отдельные пакеты и подключать по необходимости?
Как итог, пока что стараюсь не использовать эту функцию, хотя большинство коллег пользуются ею на ура. А вы используете эту возможность? Были ли с ней проблемы?
Виджеты пересобирать - норм работает же
Самым ярким примером я бы назвал go_router ... Нестабильный API, большое количество багов, проблемный генератор роутов, сложности в вебе. И все это подается под соусом лучшего решения для Flutter — проекта
Кстати, у Flutter есть такой интересный репозиторий, где они обсуждают как реализовать те или иные вещи. И в нём можно найти как они пришли к go_router.
✓ Built build/app/outputs/flutter-apk/app-release.apk (16.8MB).
Да, это больше чем пустой проект (я создал в студии пустой проект и сделал релизный билд - 4.5Мб), но если это действительно критично, то стоит использовать только нативную разработку
Моё мнение: большинство нативных приложений уже давно имеют размер выше 15Мб - поэтому размер Flutter приложения не так критичен в большинстве случаев
flutter create size
cd size
flutter build apk --release --split-per-abi
То в результате сбилдятся 3 apk:
✓ Built build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk (5.6MB).
✓ Built build/app/outputs/flutter-apk/app-arm64-v8a-release.apk (6.1MB).
✓ Built build/app/outputs/flutter-apk/app-x86_64-release.apk (6.2MB).
Конечно, это не 3Мб, но в 6Мб уже весь движок и кусочек приложения
Так же, сборка из маркета сбрасывает настройки ленты (язык, стиль, язык интерфейса) если перейти на вторую страницу в ленте. (только установил приложение и не залогинился)
Для замеров времени выполнения лучше использовать Stopwatch
Я бы рассмотрел создание области выреза через обычный Rect (или Offset + Size если удобнее) и тогда код будет проще
Или использовать пакет image, так как аргументы против не очень сильные:
1. Да, это сторонняя зависимость, но код там не сложный, что бы повторить самому + рабочий
2. Коллизия имён - обычная проблема с простым решением
3. В основном будет преобразование во flutter что бы показать то, что вышло - что выйдет меньше чем писать свои костыли
Как итог: если добавлять более 1 шага обработки изображения, то приходим к коду как отдельный пакет image
P.S. Не говорю, что не нужно пробовать делать что-то своё, просто, иногда получается слишком много не нужного кода (например, как в статье где использовался шейдер, который родился из незнания API рисования)
У Matrix4 есть уже реализованные методы для разных преобразований - почему бы не использовать их?
У Image нужно вызывать dispose, иначе она будет вечно в памяти
Минус вашего подхода - потеря оригинала изображение (в следствии рисования его на канвасе) - что ведёт к ситуации, когда вырезанный фрагмент в вашем приложении не такой же, как если бы я вырезал его инструментом, предназначенным для этого
Что если попробовать использовать FilterQuality? (его можно пробросить в drawImage через Paint.filterQuality) По идее не нужен будет шейдер
В коде нету преобразования байтов обратно в модели, а используются геттеры - это добавляет некоторый оверхед на постоянную десериализацию + компилятор не может знать, что геттеры всегда возвращают одни и те же значения
А может и завезли: для изолятов -> TransferableTypedData. Для веба -> SharedArrayBuffer
Для web, кстати, это не поможет
Если и оптимизировать, то лучше использовать
List.generate
, так как заполнение чем-то - итерация по всем элементамДа, другие структуры данных быстрее, но случайное заполнение тестовых данных не делает тест объективным
Можно попробовать вызывать его между тестами и добавить немного unsafe
Можно ли написать DI библиотеку так, что бы она в debug резолвила зависимости в рантайме (как scout) , а в release во время компиляции (как dagger)?
Это решит проблему долгих сборок для разработчиков и в тоже время конечные пользователи не будут затронуты, так как каждый пользователь не будет платить за удобство разработчика
Сам враппер пишется на Objective-C, но его можно использовать внутри Swift.
Например, у меня на скриншоте с кодом на Swift в 56 строке используется
tryBlock
из Objective-C. А сам код Objective-C со Stack Overflow. Поэтому, мы можем писать врапперы для Objective-C в Objective-C и потом использовать в SwiftЭто достаточно обычная проблема, когда в Swift используется что-то из Objective-C. Если какой-то Objective-C код падает в рантайме, то можно обернуть его в другой Objective-C код, который это отловит. Тыц
Или от меня скриншот
(Промахнулся веткой, ответ на этот комментарий)
Согласно документации,
drawWithCache
вызывает лямбду когда изменился размер рисуемой области и/или состояние, которое читается из лямбдыВ вашем случае, это сработает только между кадрами, если кадры будут рисоваться быстрее, чем вы изменяете переменную
time
Можете
print
в консоль сделать и убедится, что у вас постоянно создаются новые шейдерыЯ так понимаю, что от
Modifier.drawWithCache
нету смысла, так как происходит постоянное изменение времени, а значит, что шейдеры пересоздаются на каждую перерисовкуНе оправдываю svelte и не виню $mol
Но
В целом в корне дерева создаётся контейнер с помощью
ProviderScope
или если нужно, то создаётся ранее и потом вставляется в корень дерева с помощьюUncontrolledProviderScope
Так же, обычно провайдеры создают как top-level variables, что бы они не пересоздавались.
Так же достаточно удобная возможность - использование
riverpod
как DI:Кстати, я пересмотрел статью ещё раз и не понял как связан
LocaleNotifier
иHttpQuery
Зачем добавлять новые при каждом вызове
get
? Лучше поместить это вdioProvider
Зачем создавать контейнер для 1 зависимости?
sharedPreference
лучше брать из контейнераКак я понял, в большинстве случаев, Intellij Idea не виновата, так как они просто подключаются к Dart Analysis Server. Порой кажется, что в команде Dart не хотят что-либо улучшать. Не хочу никого оправдывать, но выходит, что IDE виновата только от части и это не отменяет проблем описанных в статье. Я бы, например, очень хотел бы, что бы локальные переменные или функции имели приоритет в выдаче, но мечтать не вредно. тыц
Наверное, это может быть решено
Виджеты пересобирать - норм работает же
Кстати, у Flutter есть такой интересный репозиторий, где они обсуждают как реализовать те или иные вещи. И в нём можно найти как они пришли к go_router.
Не вопрос:
Да, это больше чем пустой проект (я создал в студии пустой проект и сделал релизный билд - 4.5Мб), но если это действительно критично, то стоит использовать только нативную разработку
Моё мнение: большинство нативных приложений уже давно имеют размер выше 15Мб - поэтому размер Flutter приложения не так критичен в большинстве случаев
Если запустить это в терминале:
То в результате сбилдятся 3 apk:
Конечно, это не 3Мб, но в 6Мб уже весь движок и кусочек приложения
Почему отказались использовать готовые пакеты?
Например, эти пакеты (первые которые попались) умеют сканить не по одному коду за раз:
https://pub.dev/packages/barcode_scan2
https://pub.dev/packages/flutter_barcode_scanner
Почему решили не использовать FileHandle для чтения файла частями?
Функция
compute
- часть FlutterC версии 2.15 это предложение не соответствует действительности
Кстати, есть способы обойти это
Почему не 5?
Так же, сборка из маркета сбрасывает настройки ленты (язык, стиль, язык интерфейса) если перейти на вторую страницу в ленте. (только установил приложение и не залогинился)