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