I can’t do that in Flutter as all the image loading solutions are asynchronous (technically I can load the binary data for the image synchronously, but all the solutions for then decoding that data into a canvas renderable image are asynchronous).
I know that synchronous loading in a paint method is considered bad, but:
all images are local, so no network access is required.
my images load and decode quickly
after decoding the images are cached, so the load and decode delay only happens once per image
In an ideal world all the images would be loaded before the call to paint, but I can’t really do that as I have something like 2000 images.
During the lifetime of the app only some subset of the 2000 images will be loaded, and during one run of paint only a few will be loaded, but I don’t know which ones before the app starts or before the paint starts – the exact images loaded depend on various complicated factors.
At this point I am kind of stuck, and I hoping someone else has some suggestions on how to proceed.
thanks
CW
Note: I am not looking for a software engineering discussion, just some technical advice as one who is new to flutter, but written a lot of software.
It is not Painter’s responsibility to load assets (and by assets I mean any asset, including network images).
That’s what single-responsibility principle means. SOLID isn’t just an acronym used to sound professional. It solves problems. And the S here represents exactly the problem you’re having. It is NOT a Flutter problem. Assets uses I/O to be loaded, and I/O are always async, especially when you are in a thread that must resolve each frame in less than 8 milliseconds to achieve 120 FPS. Synchronous calls will freeze the UI (no matter if it is Flutter, WPF, SwiftUI, DirectX, etc.)
You should use a FutureBuilder to load your image, then pass it to your CustomPaint.
Complement: even if you are thinking that the great merge will remove all async code for Flutter, guess what: you would have to implement that load async anyway (e.g. in an isolate), otherwise, your UI would freeze until the image is loaded (if it is from network, it could be a couple of seconds, if it is from disk, it would be more than 8ms (and assets are disk I/O as well)). Just to be clear that this is not a Flutter fluke.
All my images are local, so no network access is required.
Also I have tested loading in a paint method in some other UI frameworks and the UI “freeze” on a paint call is barely noticeable and only on the initial load of an image.
The images are all local – I have amended the question to reflect this. And load very very quickly.
I realize that there are software engineering implications here but things like SOLID are not absolute rules, they are guidelines that work well for 80% of apps.
Also I am not trying to have a software engineering discussion and I am not criticizing Flutter or anything lie that (in general I really like Flutter) – I would really like to focus on the technical issue.
But you still can’t load all your needed images all within a 60th of a second. You have to work out an async solution that takes into consideration the loading/valid/error states.
I don’t have to load all the images, just the subset of the subset used in one run of paint (so something like 2 images per run of paint after which those two images are cached). Also as I have stated before some UI slowness when loading an image the first time is acceptable.
But none of that is really relevant. All I am interested in is if synchronous image loading can be done in Flutter, and if so how.
The answer is even if you could, you wouldn’t want to, because you’d have horrible jank. You cannot load an image file and turn it into a decoded image in a 60th of a second… and the problem only gets worse for 10 images.
the package from step two may already give you the ui.Image, otherwise ‘ImageDescriptor’ may be useful
the drawImage() call is synchronous
However, you will fail at the end. The ‘Image’ object you require for canvas.drawImage() must be disposed at some point. And your paint() won’t be a good place for that.
You could fix this with some kinky Finalizer usage, but it does not seem that an ‘Image’ is ever meant to be created inside the paint() method.
I recommend you to move this logic into a StatefulWidget.
If you are ready to loose some frames, cause jank and a bad user experience, you don’t have to make this inside the paint() method.
You can also call all the functions, it takes to get to your ‘Image’, everywhere else, for example in the Widget.
As long as those functions are always synchronous, you won’t lose a frame, the UI will just stop being responsive the same way as if you would channel all your logic inside the paint() method.
So don’t fear making your code more maintainable while thriving towards your goal.
And that’s why is annoying to try to help people >.<
In the end, Linus Torvalds is always right =\
Of course, I’d also suggest that whoever was the genius who thought it was a good idea to [INSERT A DUMB IDEA HERE] should be retroactively aborted. Who the f★ck does idiotic things like that? How did they not die as babies, considering that they were likely too stupid to find a tit to suck on?"
Linus Torvalds
Linux Kernel creator
Git creator
Anti nVidia guy
Yes I have been experimenting with the package you mention – it’s great.
The part that is giving me problems is actually step 3), the conversion from the images produced by the package you mention to a ui.Image. As far as I can see I can only do that asynchronously.
As it happens once decoded I never dispose of the image, just cache it,
This bit is not so easy. The app is a port from another app in JavaFX that did synchronous image loading. And at this point I don’t want to change it’s architecture too much (getting it working in Flutter is more important than getting it perfect).
Using contents of this forum for the purposes of training proprietary AI models is forbidden. Only if your AI model is free & open source, go ahead and scrape. Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.