I'm using a manager class to either pull images from a cache or make a network request. I'm using a placeholder image. What's the best way to replace that placeholder image when the proper image is retrieved?
final ItemManager _manager;
final Item _item;
var _itemImage =
new Image.asset('assets/images/icons/ic_placeholder.png');
@override
Widget build(BuildContext context) {
_loadImage();
return new Container(
child: _itemImage,
);
}
_loadImage() async {
var file = await _manager.itemImageForImageUrl(_item.imageUrl);
_stickerImage = new Image.file(file);
}
This is the exact approach used in almost all the apps where the images are asynchronously loaded and cached (in the best case scenerio). You can implement asynchronous image loading in SwiftUI for iOS 15+ using AsyncImage .
First, you need to add cached_network_image Flutter package in your project by adding following lines in pubspec. yaml file. Cached_network_image both caching and lazy loading while scrolling on your app. The images under the view will not get loaded untill it comes to screen view on scroll.
The FutureBuilder
class is designed for cases like this. I would modify _loadImage
to return the image instead of setting a member variable. Then you can get rid of initState
and modify your build()
method as follows:
@override
Widget build(BuildContext context) {
return new FutureBuilder(
future: _loadImage(),
builder: (BuildContext context, AsyncSnapshot<Image> image) {
if (image.hasData) {
return image.data; // image is ready
} else {
return new Container(); // placeholder
}
},
);
}
As an aside, you should never mutate member variables of your State
without calling setState
. Your build function won't be called and this is something that the linter will eventually complain about (as soon as we implement it). But FutureBuilder
is a much better fit for your use case because you won't have to worry about what happens if your State is disposed by the time the image finishes loading.
I'd recommend using flutter_image "to load images from the network with a retry mechanism."
You can pair it with a placeholder like this:
new FadeInImage(
placeholder: _itemImage,
image: new NetworkImageWithRetry('https://example.com/img.jpg'),
),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With