当url错误或目的地导致404时如何处理
Image.network
。
例如尝试
Image.network('https://image.tmdb.org/t/p/w92')
更新:查看使用内置方法的新准确方法,由@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 上提交一份包含可重现示例的错误报告。
我所做的是:
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
属性。
Image.network(
path.image,
width: 40,
height: 40,
errorBuilder: (BuildContext context, Object exception,
StackTrace? stackTrace) {
return const Text('😢');
},
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;
}
}
这里有一个相关链接:
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
Image(
image: NetworkImageWithRetry(
'http://ImageUrl.png',),
errorBuilder: (context, exception, stackTrack) => Icon(Icons.error,),
loadingBuilder: (context, exception, stackTrack) => CircularProgressIndicator(),
)
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!),
);
},
);
}
http和url_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();
});
},
),
)
],
),
);
}
}
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),
],
);
}
}
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',
);
}
},
);
}
}
CachedNetworkImage(
placeholder: (context, url) =>
Center(child: new CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error),
imageUrl: image,
fit: BoxFit.fill,
)