当使用Image.network()加载图片失败时,无法捕获NetworkImageLoadException异常。

6

我使用 Image.network() 方法来展示来自 URL 的图片,以下是我的实现:

Image image = Image.network(
      _auth.currentUser!.photoURL!,
      width: 100.getWidth(context),
      height: 100.getWidth(context),
      frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {
        return wasSynchronouslyLoaded
            ? child
            : _profileImagePlaceholder(context);
      },
      loadingBuilder: (context, child, loadingProgress) {
        return loadingProgress == null
            ? child
            : _profileImagePlaceholder(context);
      },
      errorBuilder: (context, error, stackTrace) {
        return _profileImagePlaceholder(context);
      },
    );

即使我设置了errorBuilder或者用try/catch包裹整个内容,仍然会显示NetworkImageLoadException

完整的异常信息

The following NetworkImageLoadException was thrown resolving an image codec:
HTTP request failed, statusCode: 403,


When the exception was thrown, this was the stack:
#0      NetworkImage._loadAsync (package:flutter/src/painting/_network_image_io.dart:99:9)
<asynchronous suspension>
...

Image provider:
  NetworkImage("https://firebasestorage.googleapis.com/v0/b/biddee-co.appspot.com/o/profiles%2FdefaultProfile.png?alt=media&token=a4a99031-aabd-4597-b075-77ecb2d3e594",
  scale: 1.0)
Image key:
  NetworkImage("https://firebasestorage.googleapis.com/v0/b/biddee-co.appspot.com/o/profiles%2FdefaultProfile.png?alt=media&token=a4a99031-aabd-4597-b075-77ecb2d3e594",
  scale: 1.0)

你找到解决方案了吗?我也有同样的问题。甚至使用 try/catch 也没有任何作用,应用程序因为“未捕获异常”而暂停。 - alex smith
你如何解决这个问题? - Alex Aung
5个回答

1

这些对我来说都不适用于当前的Flutter版本。下面是适合我的方法。

import 'package:http/http.dart';
...
final String url;
...
class _WebIconState extends State<WebIcon> {
  late Widget imgWidget;
  late bool loaded;

  @override
  void initState() {
    imgWidget = SizedBox.shrink();
    loaded = false;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    Uri? uri = Uri.tryParse(widget.url);
    if (uri == null) {
      return SizedBox.shrink();
    }
    if (!loaded) {
      () async {
        Response resp = await get(uri);
        if (resp.statusCode >= 200 &&
            resp.statusCode < 300 &&
            resp.headers["content-type"] is String &&
            resp.headers["content-type"]!.contains("image")) {
          setState(() {
            imgWidget = Image.memory(resp.bodyBytes);
            loaded = true;
          });
        }

        log("Loaded ${widget.url}");
      }();
    }

    return imgWidget;
  }

0

我也尝试了cached_network_image包和try catch,但是我找不到解决方案。然后我做了一个基本的实现。我的图片很小,所以这个解决方案暂时对我有效。

  import 'package:http/http.dart' as http;

  Map<String, Image?> imageDict = {};
  String name;
  String? profilepiclink;

  Future<Image?> fetchImage() async {
    if (imageDict[name] != null) {
      return imageDict[name];
    } else {
      final response = await http.get(Uri.parse(profilepiclink!));
      if (response.statusCode == 200) {
        // If the server did return a 200 OK response,
        // then parse the JSON.
        Image pic = Image.memory(response.bodyBytes);
        imageDict[name] = pic;
        return pic;
      } else {
        // If the server did not return a 200 OK response,
        // then throw an exception.
        return null;
      }
    }
  }

  Future<Widget> _displayProfilePic() async {
    if (profilepiclink != null) {
      Image? profilPic = await fetchImage();

      return Container(
          width: 30,
          height: 30,
          clipBehavior: Clip.hardEdge,
          child: profilPic ?? const Icon(Icons.person),
          decoration: const BoxDecoration(shape: BoxShape.circle));
    }
    return const SizedBox(width: 30, child: Icon(Icons.person));
  }

  var image = FutureBuilder<Widget>(
            future: _displayProfilePic(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return snapshot.data!;
              }
              return const Icon(Icons.person);
           })

0
在我的情况下,在生产代码中修复它的方法是在图像解析中添加一个监听器,使用onError
final image = Image.network(
  // Properties.
  errorBuilder: // ...,
);
image.image.resolve(ImageConfiguration.empty).addListener(
      ImageStreamListener(
        (_, __) { /* You can do something when the image is loaded. */ },
        onError: (_, __) {
          // Evict the object from the cache to retry to fetch it the next
          // time this widget is built.
          imageCache.evict(image.image);
        },
      ),
    );

虽然在调试/生产环境下这个方法很好用,但是在我使用HttpOverrides.runZoned()并且客户端总是返回404的测试中,测试总是失败并抛出未捕获的NetworkImageLoadException异常。

解决方法是在测试开始时监听FlutterError,并且只有在捕获到的异常不是NetworkImageLoadException时才抛出异常。

WidgetsFlutterBinding.ensureInitialized();
FlutterError.onError = (details) {
  if (details.exception is! NetworkImageLoadException) throw details.exception;
};

0
你可以使用 ErrorBuilder 来实现。
Image.network('Your image url...',
    errorBuilder: (BuildContext context, Object exception, StackTrace stackTrace) {
        return Text('Error');
    },
),

从这里找到文档链接


7
我已经像我之前所提到的那样做了,但仍然出现了异常。 - Fei Whang

-1

package:flutter/src/painting/_network_image_io.dart


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>>();
    throw image_provider.NetworkImageLoadException(statusCode: response.statusCode, uri: resolved);
}  

那个注释导致了异常。

网络可能只是暂时不可用,或者文件稍后会被添加到服务器上。避免未来的调用在检查网络失败后再次尝试解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接