【问题标题】:Flutter async method slowdown app performanceFlutter 异步方法会降低应用程序性能
【发布时间】:2019-12-21 22:52:57
【问题描述】:

我是 Flutter 的新手,我不明白我可能做错了什么。在我的应用程序中,用户可以选择更改其头像的图像。他可以从图库中选择图像或拍照。新头像保存在 _avatarImage 字段中,在 setState 方法中,_newImage 字段设置为 true,如下所示:

Future getNewAvatarImage() async {
   Image _image = .... // Take a photo or a image from Gallery
   // ...
   _avatarImage = _image;
   setState(
     () => _newImage = true;
   );
 }

在代码的一部分中,我有 compressAndUpload 方法,该方法在调用时会压缩图像并将其发送到远程服务器。此方法是异步的,只要 _newImage 字段为真,就会在 build 方法 中调用。像这样

@override
Widget build(BuildContext context) {
    if (_newImage) {
       _newImage = false;
       compressAndUpload(_avatarImage);
    }
    return Container(
       //...
       child: _avatarImage,
       //
    );

问题是如果调用compressAndUpload方法,新的头像图片会需要很长时间才能出现。如果此方法被注释掉,新的头像图像会很快出现。

    if (_newImage) {
       _newImage = false;
       // New image show quickly
       // compressAndUpload(_avatarImage);
    }

    ***********

    if (_newImage) {
       _newImage = false;
       // Image takes too long to appear
       compressAndUpload(_avatarImage);
    }

问题出在哪里? compressAndUpload 方法是异步的,因此不会导致显示新图像的延迟:

 Future<void> compressAndUpload(var image) async {
    // Compress image
    // upload image
 }

更新:

为了进一步说明,我展示了 compressAndUpload 方法的完整代码:

 Future<void> compressAndUpload(var image) async {

  var imageBytes = imagem.readAsBytesSync();

  saveImageToPreferences(base64String(imageBytes));

  var tempDir = await getTemporaryDirectory();
  var path = tempDir.path;

  // Reduce size
  img.Image image = img.decodeImage(imageBytes);
  img.Image smallerImage = img.copyResize(image, width: 1000);

  File compressedFileImage =  

  File('$path\${Explika.getAluno().id}.jpg')
   ..writeAsBytesSync(img.encodeJpg(smallerImage, quality: 50));

  String _urlsegment =  Explika.producaoFlag ? 
  'https://www.remoteserver.pt' : 'http://10.0.2.2';

  var stream = http.ByteStream(DelegatingStream.typed(
               compressedFileImage.openRead()));
  var length = await compressedFileImage.length();
  var uri = Uri.parse('$_urlsegment/explika/api/upload');

  var request = http.MultipartRequest("POST", uri);

  var multipartFile = http.MultipartFile('fotoaluno', stream, length,
      filename: '${Explika.getAluno().id}.jpg');

  request.files.add(multipartFile);

  var response;
  try {
    response = await request.send();
  } catch (e) {
    // mostrar falha de rede
    //_uploadingImagem = false;
    print(e);
    return;
  }

  //Get the response from the server
  var responseData = await response.stream.toBytes();
  var responseString = String.fromCharCodes(responseData);
  print(responseString);

}

【问题讨论】:

  • 您似乎在您的小部件的 build 方法中运行该代码,这不是正确的位置。你能分享你在哪里调用这个小部件并分享你的 compressAndUpload 方法在做什么吗?
  • 你好,若昂。问题已更新。
  • 仅仅因为compressAndUploadasync 不会让它在后台运行。您没有显示它,但毫无疑问它包含执行压缩的计算绑定代码。您将需要查看隔离,以便您可以将这种 cpu 密集型工作发布到另一个线程,并在从图像创建头像后更新和上传。
  • 另外,在异步方法中,您应该使用 await readAsBytes 而不是同步选项。
  • 在构建方法上运行该函数是您的问题的一部分。您无法控制 Flutter 何时重新渲染您的 Widget,它可能随时发生。在构建方法中调用该函数可能会导致各种问题。是否显示图像的决定应该在您返回的小部件内,而不是在它之外。用户选择图像后,应在其他地方调用 compressAndUpload 方法。

标签: asynchronous flutter setstate


【解决方案1】:

非常感谢所有 cmets。

当我发现在pickImage方法中可以设置被选中图像的最大宽度和最大高度时,问题就解决了。因此,不需要对所选图像进行压缩步骤。

【讨论】:

    猜你喜欢
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多