Flutter how to handle Image.network error (like 404 or wrong url)
FlutterHttp Status-Code-404Flutter Problem Overview
How to handle Image.network
when the url is wrong or the destination leads to 404.
for example try
Image.network('https://image.tmdb.org/t/p/w92')
Flutter Solutions
Solution 1 - Flutter
I have handled the network image issue related to 404 by using an errorBuilder.
Image.network('Your image url...',
errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
return Text('Your error widget...');
},
),
Solution 2 - Flutter
UPDATE: Look at the new accurate way which uses an inbuilt method, answered by @Niraj Phutane here which requires no plugins.
outdated old answer (before errorbuilder existed)
I recommend using cached_network_image which gives an option to add a placeholder image and also an error widget in case of a 404 or 403.
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error),
),
Solution 3 - Flutter
Instead of Network.image
use NetworkImageWithRetry
https://pub.dartlang.org/documentation/flutter_image/latest/
Example:
var avatar = Image(
image: NetworkImageWithRetry('http://example.com/avatars/123.jpg'),
);
Solution 4 - Flutter
You can display image from assets when you found 404 or any other error while loading image.
What I have done is:
FadeInImage(
image: NetworkImage("imageUrl"),
placeholder: AssetImage(
"assets/images/placeholder.jpg"),
imageErrorBuilder:
(context, error, stackTrace) {
return Image.asset(
'assets/images/error.jpg',
fit: BoxFit.fitWidth);
},
fit: BoxFit.fitWidth,
)
Check imageErrorBuilder
property.
Solution 5 - Flutter
You can use ImageStream
to handle errors.
class CustomProductImage extends StatefulWidget {
final String image;
const CustomProductImage(this.image);
@override
State<CustomProductImage> createState() => _CustomProductImageState();
}
class _CustomProductImageState extends State<CustomProductImage> {
Widget mainWidget = const CircularProgressIndicator(); // Placeholder widget
@override
void initState() {
super.initState();
Image image = Image.network(widget.image, width: 50, height: 50);
final ImageStream stream = image.image.resolve(ImageConfiguration.empty);
stream.addListener(ImageStreamListener((info, call) {
if (!completer) {
completer = true;
setState(() {
mainWidget = image;
});
}
}, onError: (dynamic exception, StackTrace? stackTrace) {
print('Error is $exception , stack is $stackTrace');
setState(() {
mainWidget = const Icon(Icons.error); // Error Widget
});
}));
}
@override
Widget build(BuildContext context) {
return mainWidget;
}
}
Solution 6 - Flutter
It's weird but you can't easily handle errors correctly with Image.Provider. Use this handy package: https://pub.dev/packages/flutter_advanced_networkimage
Then in you code:
backgroundImage: AdvancedNetworkImage(
"YOUR IMAGE URL",
fallbackAssetImage: "YOUR DEAULT ASSERT IMAGE eg:assets/default.png"
)
Solution 7 - Flutter
I had the same problem, but, I solved it using the property 'imageErrorBuilder' of the FadeInImage class.
Here is a link about that: https://api.flutter.dev/flutter/widgets/Image/errorBuilder.html
The example was made for Image.network(), but it also work for FadeInImage.
Here's my code:
FadeInImage(
imageErrorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
print('Error Handler');
return Container(
width: 100.0,
height: 100.0,
child: Image.asset('assets/img/no_disponible.jpg'),
);
},
placeholder: AssetImage('assets/img/loading.gif'),
image: NetworkImage(product.getImg()),
fit: BoxFit.cover,
height: 100.0,
width: 100.0,
),
The function of imageErrorBuilder will be execute for example, if the direction of the page doesn't exist.
I'm using Flutter 1.20.1
Solution 8 - Flutter
Can use errorBuilder from Image.network or Image.asset
Image.network(
path.image,
width: 40,
height: 40,
errorBuilder: (BuildContext context, Object exception,
StackTrace? stackTrace) {
return const Text('š¢');
},
Solution 9 - Flutter
I used the basic Image widget and added an error builder for errors and a loadingBuilder for loading status and for the actual image I used NetworkImageWithRetry so that it will try to load the image many times and give you an error at the end if it couldn't load the image.
Image(
image: NetworkImageWithRetry(
'http://ImageUrl.png',),
errorBuilder: (context, exception, stackTrack) => Icon(Icons.error,),
loadingBuilder: (context, exception, stackTrack) => CircularProgressIndicator(),
)
Solution 10 - Flutter
For those who are using firebase storage
The above methods didn't help me at all.
When the object is not found in firebase, I got an exception "Null is not a type of List<int>"
.
So I decided to verify if the Unit8List values are valid or not.
If it's valid then we are ready to show the image otherwise use any widgets as placeholder.
Future<String?> getImgUrl()async{
//Storage structre: avatars/+919999999999/avatar.jpg
//Permanent url of an image without tokens
//%2F means "/"
//%2B mans "+"
String imgUrl = "https://firebasestorage.googleapis.com/v0/b/yourFIrebaseProjectID/o/avatars%2F%2B919999999999%2Favatar.jpg?alt=media";
try {
Uint8List bytes = (await NetworkAssetBundle(Uri.parse(imgUrl)).load(imgUrl)).buffer.asUint8List();
print("The image exists!");
return imgUrl;
} catch (e) {
print("Error: $e");
return null;
}
}
Widget futureBulder(){
return FutureBuilder(
future: getImgUrl(),
builder: (BuildContext context, AsyncSnapshot<String?> snapshot) {
bool error = snapshot.data==null;
//I use NetworkImage for demonstration purpose, use it whatever widget u want
return CircleAvatar(
backgroundImage: error? null : NetworkImage(snapshot.data!),
);
},
);
}
Solution 11 - Flutter
I have implemented this StatefulWidget for the same case, hope this helps!!!
class NetworkImageHandlerViewer extends StatefulWidget {
final String imageURL;
bool errorFoundInImageLoad = false;
NetworkImageHandlerViewer({
Key key,
@required this.imageURL,
}) : super(key: key);
@override
_NetworkImageHandlerViewerState createState() =>
_NetworkImageHandlerViewerState();
}
class _NetworkImageHandlerViewerState extends State<NetworkImageHandlerViewer> {
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
height: 200,
// height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
// color: Colors.black,
child: (widget.errorFoundInImageLoad)
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Unable To Fetch Image",
),
IconButton(
iconSize: 40,
onPressed: () {
setState(() {
if (mounted) {
print("reloading image again");
setState(() {
widget.errorFoundInImageLoad = false;
});
}
});
},
icon: Icon(Icons.refresh),
),
Text(
"Tap Refresh Icon To Reload!!!",
),
],
)
: Image.network(
// widget.question.fileInfo[0].remoteURL,
widget.imageURL,
//
loadingBuilder: (context, child, loadingProgress) =>
(loadingProgress == null)
? child
: Center(
child: CircularProgressIndicator(),
),
errorBuilder: (context, error, stackTrace) {
Future.delayed(
Duration(milliseconds: 0),
() {
if (mounted) {
setState(() {
widget.errorFoundInImageLoad = true;
});
}
},
);
return SizedBox.shrink();
},
),
),
SizedBox(height: 25),
],
);
}
}
Solution 12 - Flutter
https://pub.dev/packages/extended_image
the plugin makes it easy to handle errors in Network image load
import 'package:flutter/material.dart';
import 'package:extended_image/extended_image.dart';
class ImageHolder extends StatefulWidget {
const ImageHolder(
{Key? key,
required this.url,
required this.imageHeight,
required this.imageWidth})
: super(key: key);
final String url;
final double imageHeight;
final double imageWidth;
@override
_ImageHolderState createState() => _ImageHolderState();
}
class _ImageHolderState extends State<ImageHolder>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 3),
lowerBound: 0.0,
upperBound: 1.0);
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ExtendedImage.network(
widget.url,
fit: BoxFit.contain,
cache: true,
loadStateChanged: (ExtendedImageState state) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
_controller.reset();
return Image.asset(
'assets/images/loading.gif',
fit: BoxFit.fill,
);
case LoadState.completed:
_controller.forward();
return FadeTransition(
opacity: _controller,
child: ExtendedRawImage(
image: state.extendedImageInfo?.image,
width: widget.imageWidth,
height: widget.imageHeight,
),
);
case LoadState.failed:
_controller.reset();
state.imageProvider.evict();
return Image.asset(
'assets/images/failed.jpg',
);
}
},
);
}
}
Solution 13 - Flutter
CachedNetworkImage(
placeholder: (context, url) =>
Center(child: new CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
imageUrl: image,
fit: BoxFit.fill,
)