Flutter:如何处理带有无效图像数据异常的 NetworkImage?

Shl*_*ith 5 error-handling dart flutter

我正在尝试使用 NetworkImage 作为容器的 BoxDecoration 中的图像。传递给 NetworkImage 的 url 有时会包含错误的图像类型(该 url 有效且正确,但指定 url 处的实际图像是错误的),从而导致错误。

为了处理这种情况,我设置了一个方法,该方法使用 try-catch 块,如果成功则返回 NetworkImage,如果出现错误则返回预设的 AssetImage。try-catch 块不处理此异常,并抛出错误,而不是返回 catch 中指定的 AssetImage。

我已经看到 Image.network 有一个 onError 参数,看起来它可以解决问题,但是 Image.network 的类型为“Image”,而 BoxDecoration 需要一个“ImageProvider”(NetworkImage、AssetImage),因此这无济于事这个案例。

处理此错误的最佳方法是什么,以便我可以在 NetworkImage 抛出错误的情况下显示 AssetImage?

这是持有 BoxDecoration 的小部件,我在其中调用我创建的方法来处理获取 NetworkImage:

class CharacterPreviewCard extends StatelessWidget {
  final CharacterPreview character;
  const CharacterPreviewCard({Key? key, required this.character})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        context.router
            .push(CharacterDetailsRoute(characterId: character.characterId));
      },
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            height: 171,
            width: 171,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(16),
              color: Colors.black,
              image: DecorationImage(
                image: getCharacterAvatar(character.characterAvatarUrl),
                fit: BoxFit.fill,
              ),
            ),
          ),
          const SizedBox(height: smallMargin),
          Padding(
            padding: const EdgeInsets.only(left: smallMargin),
            child: SizedBox(
              width: 165,
              child: Text(
                character.characterName,
                style: Theme.of(context).textTheme.bodyLarge,
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
              ),
            ),
          ),
        ],
      ),
    );
  }
Run Code Online (Sandbox Code Playgroud)

这是方法“getCharacterAvatar”,它应该返回 NetworkImage 或 AssetImage:

ImageProvider<Object> getCharacterAvatar(String url) {
    try {
      final image = NetworkImage(url);
      return image;
    } catch (e) {
      return const AssetImage('assets/images/village-not-found-logo.png');
    }
  }
Run Code Online (Sandbox Code Playgroud)

这是调试控制台中的错误:

The following _Exception was thrown resolving an image codec:
Exception: Invalid image data

When the exception was thrown, this was the stack
#0      _futurize (dart:ui/painting.dart:5718:5)
#1      ImageDescriptor.encoded (dart:ui/painting.dart:5574:12)
#2      instantiateImageCodec (dart:ui/painting.dart:2056:60)
<asynchronous suspension>
Image provider: NetworkImage("https://narutoql.s3.amazonaws.com/Hana.jpg", scale: 1.0)
Image key: NetworkImage("https://narutoql.s3.amazonaws.com/Hana.jpg", scale: 1.0)
Run Code Online (Sandbox Code Playgroud)

Shl*_*ith 1

目前,无法使用NetworkImage或捕获错误Image.network。有关更多信息,请访问: https: //github.com/flutter/flutter/issues/20910

感谢 Tom3652 的评论建议使用 ,CachedNetworkImage我能够找到一个解决方案,该解决方案使用CachedNetworkImageerrorWidget参数的小部件来显示AssetImage抛出错误的时间。

Container用自定义小部件替换了NetworkImage以 为DecorationImage参数的(以最小化文件中的代码)。自定义小部件返回CachedNetworkImage.

这是对我有用的解决方案:

class PreviewCardImage extends StatelessWidget {
  final String url;
  final AssetImage errorImage;
  const PreviewCardImage({
    Key? key,
    required this.url,
    required this.errorImage,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CachedNetworkImage(
      imageUrl: url,
      imageBuilder: (context, imageProvider) => Container(
        height: 171,
        width: 171,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16),
          color: Colors.black,
          image: DecorationImage(
            image: imageProvider,
            fit: BoxFit.fill,
          ),
        ),
      ),
      placeholder: (context, url) => const CircularProgressIndicator(),
      errorWidget: (context, url, error) => Container(
        height: 171,
        width: 171,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16),
          color: Colors.black,
          image: DecorationImage(
            image: errorImage,
            fit: BoxFit.fill,
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)