I am facing some issues with loading images from URLs in Flutter. Here is my code:
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Center(
child: Image.network(
'https://www.example.com/no-image.jpg', // this image doesn't exist
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
color: Colors.amber,
alignment: Alignment.center,
child: const Text(
'Whoops!',
style: TextStyle(fontSize: 30),
),
);
},
),
),
);
}
I am using Image.network
to receive images from a given URL but as the URL does not exist the widget throws a 404 exception, even though the errorBuilder
parameter is defined. It is not only for 404 exceptions but any network connection errors.
Source of exception (flutter file: .../_network_image_io.dart
):
Future<ui.Codec> _loadAsync(
NetworkImage key,
StreamController<ImageChunkEvent> chunkEvents,
image_provider.DecoderCallback decode,
) async {
try {
assert(key == this);
final Uri resolved = Uri.base.resolve(key.url);
final HttpClientRequest request = await _httpClient.getUrl(resolved);
headers?.forEach((String name, String value) {
request.headers.add(name, value);
});
final HttpClientResponse response = await request.close();
if (response.statusCode != HttpStatus.ok) {
// The network may be only temporarily unavailable, or the file will be
// added on the server later. Avoid having future calls to resolve
// fail to check the network again.
await response.drain<List<int>>(<int>[]);
throw image_provider.NetworkImageLoadException(
statusCode: response.statusCode, uri: resolved);
}
final Uint8List bytes = await consolidateHttpClientResponseBytes(
response,
onBytesReceived: (int cumulative, int? total) {
chunkEvents.add(ImageChunkEvent(
cumulativeBytesLoaded: cumulative,
expectedTotalBytes: total,
));
},
);
if (bytes.lengthInBytes == 0)
throw Exception('NetworkImage is an empty file: $resolved');
return decode(bytes);
} catch (e) {
// Depending on where the exception was thrown, the image cache may not
// have had a chance to track the key in the cache at all.
// Schedule a microtask to give the cache a chance to add the key.
scheduleMicrotask(() {
PaintingBinding.instance!.imageCache!.evict(key);
});
print(e);
rethrow; // <<<<<<<< Exception throw here: NetworkImageLoadException (HTTP request failed, statusCode: 404, https://www.example.com/no-image.jpg)
} finally {
chunkEvents.close();
}
}
I am wondering if it is a bug or I've made a mistake.
CodePudding user response:
Yes, you are correct with the implementation. So the thing is, NetworkImage tries to load the image and fails to load it. And hence, the _loadAsync()
method rethrows
the exception. Now, as you have provided errorBuilder
, the framework uses that widget to show when an exception occurs. Hence, you are getting an exception that is rethrown from the framework but is handled as you have provided errorBuilder
. Now, if you remove the errorBuilder
you will get the exception logged in debug console, as well as the user, will be able to see that red exception screen if in debug mode and grey screen in release mode.
So, you are correct with the implementation as well as your doubt, but you missed the exact explanation of errorBuilder
.
I hope this made your doubt clear!