Flutter 如何处理 Image.network 错误(如 404 或错误的 url)

问题描述 投票:0回答:15

当url错误或目的地导致404时如何处理

Image.network

例如尝试

Image.network('https://image.tmdb.org/t/p/w92')
    
flutter http-status-code-404
15个回答
112
投票
我已经使用errorBuilder处理了与404相关的网络图像问题。

Image.network('Your image url...', errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) { return Text('Your error widget...'); }, ),

errorBuilder 属性


24
投票

更新:查看使用内置方法的新准确方法,由@Niraj Phutane here回答,无需插件。


旧答案(在错误生成器存在之前)

我建议使用

cached_network_image,它提供了添加占位符图像的选项,以及在 404 或 403 情况下添加错误小部件。

CachedNetworkImage( imageUrl: "http://via.placeholder.com/350x150", placeholder: (context, url) => new CircularProgressIndicator(), errorWidget: (context, url, error) => new Icon(Icons.error), ),

编辑:如果您的应用程序在 url 为 404 时崩溃,faq 有一个与此相关的条目,请在 github 上的 cached_network_image 上提交一份包含可重现示例的错误报告。


15
投票
当加载图像时发现 404 或任何其他错误时,您可以显示资源中的图像。

我所做的是:

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, )
检查 

imageErrorBuilder

 属性。


10
投票
代替

Network.image

 使用 
NetworkImageWithRetry


https://pub.dartlang.org/documentation/flutter_image/latest/

示例:

var avatar = Image( image: NetworkImageWithRetry('http://example.com/avatars/123.jpg'), );
    

9
投票
可以使用 Image.network 或 Image.asset 中的 errorBuilder

Image.network( path.image, width: 40, height: 40, errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) { return const Text('😢'); },
    

5
投票
您可以使用

ImageStream

 来处理错误。

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; } }
    

3
投票
这很奇怪,但您无法轻松地使用 Image.Provider 正确处理错误。 使用这个方便的包:

https://pub.dev/packages/flutter_advanced_networkimage

然后在你的代码中:

backgroundImage: AdvancedNetworkImage( "YOUR IMAGE URL", fallbackAssetImage: "YOUR DEAULT ASSERT IMAGE eg:assets/default.png" )
    

2
投票
我遇到了同样的问题,但是,我使用 FadeInImage 类的属性“imageErrorBuilder”解决了它。

这里有一个相关链接:

https://api.flutter.dev/flutter/widgets/Image/errorBuilder.html

该示例是为 Image.network() 制作的,但它也适用于 FadeInImage。

这是我的代码:

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, ),
例如,如果页面方向不存在,将执行imageErrorBuilder函数。

我使用的是 Flutter 1.20.1


2
投票
我使用了基本的图像小部件,并添加了一个错误生成器和一个用于加载状态的loadingBuilder,对于实际图像,我使用了NetworkImageWithRetry,这样它会尝试多次加载图像,如果不能的话,最后会给出一个错误不加载图像。

Image( image: NetworkImageWithRetry( 'http://ImageUrl.png',), errorBuilder: (context, exception, stackTrack) => Icon(Icons.error,), loadingBuilder: (context, exception, stackTrack) => CircularProgressIndicator(), )
    

2
投票
对于那些使用

firebase 存储的人

以上方法对我完全没有帮助。 当在 firebase 中找不到对象时,我遇到了异常"Null is not a type of List<int>"

。
所以我决定验证 Unit8List 值是否有效。
如果它有效,那么我们就准备显示图像,否则使用任何小部件作为占位符。

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!), ); }, ); }
    

2
投票
我在学习flutter(不是web)时遇到了这个问题。在尝试了该线程中给出的所有无效选项后,我找到了解决方案。如果地址错误或找不到资源,它们都会将错误打印到控制台。要使用我的解决方案,您需要安装两个插件:

httpurl_launcher(第二个插件仅需要在模拟器中打开指向此主题的链接)。请务必阅读有关使用插件的最新说明。你问怎么玩?根据需要更改输入图像 URL 字段中的地址!如果发现错误请报告。

import 'package:http/http.dart' as http; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Image 404', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { static const _problemDescriptionUrl = 'https://stackoverflow.com/questions/52568872/flutter-how-to-handle-image-network-error-like-404-or-wrong-url'; String imageUrl = 'https://repository-images.githubusercontent.com/90528830/018a6400-d879-11e9-92b4-492c61d9bc32'; late Future<Widget> futureWidget; Future<Widget> fetchImage() async { if (imageUrl.startsWith('https://') && Uri.tryParse(imageUrl) != null && Uri.tryParse(imageUrl)!.hasAbsolutePath) { final response = await http.get(Uri.parse(imageUrl)); if (response.statusCode == 200 && (response.headers.keys.contains('content-type') && !response.headers['content-type']!.contains('text/html'))) { // If the server did return a 200 OK response, // then parse the data. return Image.memory(response.bodyBytes, fit: BoxFit.cover); } else { // If the server did not return a 200 OK response, // then return const Text('Failed to load Image'); } } return const Text('Failed to load Image'); } @override void initState() { futureWidget = fetchImage(); super.initState(); } void _launchUrl() async { if (!await launchUrl(Uri.tryParse(_problemDescriptionUrl)!)) { throw 'Could not launch $_problemDescriptionUrl'; } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Image.network Error 404 Solution'), ), body: Column( children: [ TextButton( onPressed: _launchUrl, child: const Text('The problem described here')), Container( padding: const EdgeInsets.all(8), alignment: Alignment.center, width: double.infinity, height: 200, child: FutureBuilder<Widget>( future: futureWidget, builder: (context, snapshot) { if (snapshot.hasData) { return snapshot.data!; } else if (snapshot.hasError) { return Text('${snapshot.error}'); } // By default, show a loading spinner. return const CircularProgressIndicator(); }, ), ), Form( child: TextFormField( decoration: const InputDecoration(labelText: 'Image URL'), initialValue: imageUrl, maxLines: 3, keyboardType: TextInputType.url, textInputAction: TextInputAction.done, onChanged: (val) { setState(() { imageUrl = val; futureWidget = fetchImage(); }); }, ), ) ], ), ); } }
    

1
投票
这就是我正在寻找的东西,但它是暂时的......它忽略 404 错误异常并返回 null。

FlutterError.onError = (FlutterErrorDetails details) { if (details.library == 'image resource service') { return; } FirebaseCrashlytics.instance.recordFlutterFatalError(details); };
了解更多信息

errorBuilder 因图像数据无效而引发异常#107416


0
投票
我已经针对相同的情况实现了这个 StatefulWidget,希望这有帮助!!!

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), ], ); } }
    

0
投票

https://pub.dev/packages/extended_image

该插件可以轻松处理网络图像加载中的错误

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', ); } }, ); } }
    

0
投票
CachedNetworkImage( placeholder: (context, url) => Center(child: new CircularProgressIndicator()), errorWidget: (context, url, error) => Icon(Icons.error), imageUrl: image, fit: BoxFit.fill, )
    
© www.soinside.com 2019 - 2024. All rights reserved.