-
Notifications
You must be signed in to change notification settings - Fork 26.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flutter web: The Image.memory makes the web page freeze for a period of time when uploading/downloading an image that has a big size #102828
Comments
I tried precacheImage. The web still freezes for a while when I assigned the Image widget in the x parameter before using precacheImage(x.image, context). The precacheImage help to make the web smooth when swapping the widget from another widget to Image.memory. I think the problem is Image.memory. |
Hi @SittiphanSittisak, Thanks for filing the issue. Please share a minimal and complete reproducible code along with the output of |
Thank you for your response. test link: In this case, I can use the precacheImage. But in my project, the image that was used in the Image.memory() comes from an upload or API(unknown image size). Converting an image to byte or putting the image bytes in the Image.memory() doesn't make the app freeze, The app will be freezing when showing the Image.memory(). flutter doctor:
minimal code:
Adding the folder asset/102828 with 3 images and add
images from https://unsplash.com/photos/CdAmQAko9As:
in pubspec.yml look like:
|
Hi @SittiphanSittisak, let's break down your question as below:
There are some tips that may help you:
Sample code:import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const Page102828(),
);
}
}
class Page102828 extends StatefulWidget {
const Page102828({Key? key}) : super(key: key);
@override
_Page102828State createState() => _Page102828State();
}
class _Page102828State extends State<Page102828> {
bool mediumToggle = true, largeToggle = true, titanToggle = true, putImgInWidgetToggle = false;
List<int> imgMedium = [], imgLarge = [], imgTitan = [];
Widget? putImgInWidget;
Future getImg() async {
imgMedium = (await rootBundle.load('asset/102828/medium.jpg')).buffer.asUint8List();
imgLarge = (await rootBundle.load('asset/102828/large.jpg')).buffer.asUint8List();
imgTitan = (await rootBundle.load('asset/102828/titan.jpg')).buffer.asUint8List();
}
void testPutImgInWidget(img) {
putImgInWidgetToggle = false;
putImgInWidget = null;
putImgInWidget = SizedBox(
width: 100,
height: 100,
child: Image.memory(Uint8List.fromList(img),
width: double.infinity, height: double.infinity, fit: BoxFit.scaleDown));
}
@override
void initState() {
getImg();
super.initState();
}
Widget showImg({required bool isTxt, required String txt, required List<int> img}) {
return Container(
margin: const EdgeInsets.all(20),
height: 100,
width: 100,
color: Colors.brown,
child: Center(
child: isTxt
? Text(txt)
: Image.memory(Uint8List.fromList(img),
width: double.infinity,
height: double.infinity,
fit: BoxFit.scaleDown,
frameBuilder: (
BuildContext context,
Widget child,
int? frame,
bool wasSynchronouslyLoaded,
) {
if (wasSynchronouslyLoaded) return child;
return AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: frame != null
? child
: const SizedBox(
height: 60,
width: 60,
child: CircularProgressIndicator(strokeWidth: 6),
),
);
},
errorBuilder: (context, error, stackTrace) =>
const Center(child: Icon(Icons.error, color: Colors.red, size: 20)))),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
alignment: Alignment.center,
child: SingleChildScrollView(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
const SizedBox(
width: 100, height: 100, child: CircularProgressIndicator(color: Colors.red, strokeWidth: 4)),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
InkWell(
onTap: () => setState(() {
largeToggle = true;
titanToggle = true;
mediumToggle = !mediumToggle;
}),
child: const Icon(Icons.swap_horizontal_circle_rounded, size: 20)),
InkWell(onTap: () => testPutImgInWidget(imgMedium), child: const Text("Put imgMedium to testWidget")),
showImg(isTxt: mediumToggle, txt: "Medium 1920 x 1458", img: imgMedium),
InkWell(
onTap: () => setState(() {
mediumToggle = true;
titanToggle = true;
largeToggle = !largeToggle;
}),
child: const Icon(Icons.swap_horizontal_circle_rounded, size: 20)),
InkWell(onTap: () => testPutImgInWidget(imgLarge), child: const Text("Put imgLarge to testWidget")),
showImg(isTxt: largeToggle, txt: "Large 2400 x 1823", img: imgLarge),
InkWell(
onTap: () => setState(() {
mediumToggle = true;
largeToggle = true;
titanToggle = !titanToggle;
}),
child: const Icon(Icons.swap_horizontal_circle_rounded, size: 20)),
InkWell(onTap: () => testPutImgInWidget(imgTitan), child: const Text("Put imgTitan to testWidget")),
showImg(isTxt: titanToggle, txt: "Titan 4096 x 3112", img: imgTitan),
InkWell(
onTap: () => setState(() => putImgInWidgetToggle = true), child: const Text("show testWidget")),
putImgInWidgetToggle
? putImgInWidget ?? Container(height: 100, width: 100, color: Colors.brown)
: Container(height: 100, width: 100, color: Colors.brown),
],
),
],
),
),
)),
);
}
}
I tried to run your sample code and found that it's an issue by
Demo - freeze102828.movDemo - no freeze102828_html.movflutter doctor -v[✓] Flutter (Channel stable, 2.10.5, on macOS 12.2.1 21D62 darwin-x64, locale en-VN)
• Flutter version 2.10.5 at /Users/huynq/Documents/GitHub/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 5464c5bac7 (3 weeks ago), 2022-04-18 09:55:37 -0700
• Engine revision 57d3bac3dd
• Dart version 2.16.2
• DevTools version 2.9.2
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
• Android SDK at /Users/huynq/Library/Android/sdk
• Platform android-31, build-tools 31.0.0
• ANDROID_HOME = /Users/huynq/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• CocoaPods version 1.11.3
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2020.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
[✓] Android Studio (version 4.1)
• Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.7042882/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
[✓] Android Studio
• Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/203.7185775/Android Studio Preview.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6842174)
[✓] IntelliJ IDEA Community Edition (version 2020.3.3)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
[✓] VS Code (version 1.66.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.40.0
[✓] Connected device (4 available)
• MI 8 Lite (mobile) • 4f54c54e • android-arm64 • Android 10 (API 29)
• iPhone 13 (mobile) • 5F5D609C-3B0B-4C48-872C-961928157361 • ios • com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator)
• macOS (desktop) • macos • darwin-x64 • macOS 12.2.1 21D62 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 101.0.4951.54
[✓] HTTP Host Availability
• All required HTTP hosts are available
• No issues found!
[✓] Flutter (Channel master, 2.13.0-0.0.pre.987, on macOS 12.2.1 21D62 darwin-x64, locale en-VN)
• Flutter version 2.13.0-0.0.pre.987 at /Users/huynq/Documents/GitHub/flutter_master
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 0656a5c033 (4 hours ago), 2022-05-08 18:24:04 -0400
• Engine revision c930e64a13
• Dart version 2.18.0 (build 2.18.0-98.0.dev)
• DevTools version 2.13.1
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
• Android SDK at /Users/huynq/Library/Android/sdk
• Platform android-31, build-tools 31.0.0
• ANDROID_HOME = /Users/huynq/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• CocoaPods version 1.11.3
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2020.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
[✓] Android Studio (version 4.1)
• Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/201.7042882/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
[!] Android Studio
• Android Studio at /Users/huynq/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-1/203.7185775/Android Studio Preview.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
✗ Unable to find bundled Java version.
• Try updating or re-installing Android Studio.
[✓] IntelliJ IDEA Community Edition (version 2020.3.3)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
[✓] VS Code (version 1.66.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.40.0
[✓] Connected device (4 available)
• MI 8 Lite (mobile) • 4f54c54e • android-arm64 • Android 10 (API 29)
• iPhone 13 (mobile) • 5F5D609C-3B0B-4C48-872C-961928157361 • ios • com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator)
• macOS (desktop) • macos • darwin-x64 • macOS 12.2.1 21D62 darwin-x64
• Chrome (web) • chrome • web-javascript • Google Chrome 101.0.4951.54
[✓] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 1 category.
|
Can you please try this on a newer Flutter version? We recently introduced WebCodecs-based image decoding. I profiled the sample app and noticed that it still uses the WASM codecs. If the WebCodecs-based decoder still janks we'll take a look. Otherwise, our recommendation is to use WebCodecs. While not all browsers support them, we expect as browser support matures this problem will gradually go away. As a workaround, you could try decoding images in a WebWorker. |
I'm sorry for replying so late.
|
I'm sorry for replying so late.
I don't know about "decoding images in a WebWorker". After I updated the flutter version, I tried to rebuild the project and It's smooth like this (after 34sec is the new flutter version): You can test by following this link: |
After using
|
@SittiphanSittisak yes, the new version of Flutter will try to use the I am going to keep this issue open as a feature request for processing large images after decoding. I don't have a solution though. At some point the image has to make it into the WebGL context, and I'm not aware of a non-blocking way to do this. Maybe WebGPU will have something. So this may take a while to fully fix. |
how to final imageMemory = MemoryImage(Uint8List.fromList(imageData)); to convert image link in flutter |
@ShanibhanushaInfosoft If you mean how to convert an image from the URL path to byte, this is how:
|
When a user uploads an image that has a big size, the application will freeze at the moment(Is the app calculating?).
How to fix it to smooth. The Image.network has a leadingBuilder property but the Image.memory doesn't have this property.
And another similar problem. When the Image.memory is assigned in the x parameter and another widget is y. When I use setState for swapping the widget x and y in the Card widget. The web always freezes for a while that the widget swap from y to x(From another widget to Image.memory widget that contains the image with big size).
For the example:
Screen.Recording.29-4-2565.23-11-18.mp4
How to fix this?
I want to make the app work smooth.
If the image has a big size, the app shows an indicator that when the app is processing.
And the app shouldn't reload the image widget every time that the widget was toggled by setState.
The text was updated successfully, but these errors were encountered: