Reputation: 6846
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);
}
Upvotes: 6
Views: 13802
Reputation: 21295
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'),
),
Upvotes: 3
Reputation: 116728
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.
Upvotes: 11