Могу ли я запускать функции «image.dart» в фоновом режиме

#image #flutter #dart

#изображение #flutter #dart

Вопрос:

Я хочу отображать загрузочный виджет при сжатии выбранного изображения. Я использую пакет «image.dart» для выбора изображения с помощью ImagePicker.getImage().
Затем я хочу отобразить загрузочный виджет во время сжатия изображения, а по завершении отобразить сжатое изображение.
Мой код в принципе работает, мой загрузочный виджет классный (спасибо spinkit), я могу выбрать любое изображение, сжать его и отобразить новое, но во время сжатия изображения происходит небольшая остановка (2-3 секунды).
Итак, я пытаюсь установить загрузочный виджет, чтобы пользователь не паниковал и не нажимал 10 000 раз, чтобы выбрать нужное изображение, но я пока не совсем освоился с асинхронным кодом.

Вот мой код :

 import 'package:image/image.dart' as Img;
  
   @override
  Widget build(BuildContext context) {
    if (loading == true) {
      return LoadingScreen();
    } else {
      return Scaffold(
        backgroundColor: Colors.brown[300],
        body: Column(
          children: [
            SizedBox(
              height: 50,
            ),
            RaisedButton(
              child: Text('Select an image'),
              onPressed: () async {
                await getImage();
                // You can see here that I'm trying to trigger the loading widget
                setState(() {
                  loading = true;
                });
                compressImage();
                // And I want to disable the loading widget here, after the compression
                setState(() {
                  loading = false;
                });
              },
            ),
            SizedBox(
              height: 10,
            ),
            pickedImage != null ? printSelectedImage() : Center(child: Text('Please select an image')),
          ],
        ),
      );
    }
  }
  
 getImage() async {
    pickedFile = await picker.getImage(source: ImageSource.gallery);
}
  
 compressImage() async {
    Img.Image selectedImage = Img.decodeJpg(File(pickedFile.path).readAsBytesSync());
    if (selectedImage.width > selectedImage.height) {
      Img.Image compressedImage = Img.copyResize(selectedImage, width: 500);
      File(pickedFile.path).writeAsBytesSync(Img.encodePng(compressedImage));
    } else {
      Img.Image compressedImage = Img.copyResize(selectedImage, height: 500);
      File(pickedFile.path).writeAsBytesSync(Img.encodePng(compressedImage));
    }

    if (pickedFile.path != null) {
      setState(() {
        pickedImage = pickedFile.path;
      });
    }
  }
  

Но результат тот же, экран по-прежнему застревает в селекторе файлов во время сжатия, а затем напрямую отображает сжатое изображение.
Я начал изучать dart / Flutter 2 недели назад, поэтому мне не хватает некоторых фундаментальных принципов языка dart? Я не вижу чего-то очевидного?
Спасибо за чтение

Ответ №1:

Создание чего-либо async не перемещает это в какой-то волшебный фоновый поток. Dart использует изолированные объекты, которые в основном являются контекстом выполнения, в котором может выполняться код dart. У Flutter есть единственный изолят, который запускает ваше приложение, если вы выполняете в нем слишком много работы, ваше приложение замедляется или пропускает кадры.

Вы можете создавать другие изоляты для выполнения вычислений и разгрузки работы, а также обмениваться данными между изолятами, передавая сообщения с примитивным содержимым туда и обратно. Недостаток Flutter в том, что другие изоляты не имеют доступа к плагинам Flutter, поэтому многие вещи там не работают. Есть способы обойти это, но они довольно сложны.

Самый простой способ запустить изоляцию — это compute(callback, message) функция.

Создайте изолированный файл, запустите callback этот изолированный файл, передав его message и
(в конечном итоге) верните значение, возвращенное callback .

Я не уверен, что image/image.dart библиотека использует плагин или какие-то другие функции, которые недоступны ( dart:ui например), вы можете попробовать загрузить сжатие изображения в обратный вызов. Если произойдет сбой с помощью MissingPluginException или чего-то подобного, то это не сработает. Помните, вы можете передавать только примитивные сообщения, поэтому вы не можете указывать путь pickedFile , только передавать в качестве аргумента.

Однако для вашей проблемы может быть более простое решение. Средство выбора изображений принимает параметры для максимальной ширины / высоты и качества. Однако, если вам нужно, чтобы изображение было закодировано в формате PNG, вам нужно создать комплексное решение самостоятельно.

Комментарии:

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

2. После беглого просмотра здесь эти примитивы могут передавать друг другу значения null, num, bool, double или String. Так что я все равно не смог бы вернуть все изображение?

3. Вы бы выбрали изображение в основном изолированном файле, а затем сжали его в compute, передав path в качестве аргумента. Средство выбора изображения не займет больше времени, если вы передадите размер в качестве начального аргумента.