Home > Back-end >  CachedNetwork Image - No host specified in URI
CachedNetwork Image - No host specified in URI

Time:12-04

I'm using a cached network image to load in an image from firebase and if the image is URL is null it loads a circle avatar with an icon in it.

It works fine in the emulator but it always posts the error when image url is null:

I/flutter ( 6907): CacheManager: Failed to download file from  with error:
I/flutter ( 6907): Invalid argument(s): No host specified in URI 

when image url is not null:

I/flutter ( 6907): CacheManager: Failed to download file from  with error:
I/flutter ( 6907): Invalid argument(s): No host specified in URI 

══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
The following ArgumentError was thrown resolving an image codec:
Invalid argument(s): No host specified in URI

When the exception was thrown, this was the stack:
#0      _HttpClient._openUrl (dart:_http/http_impl.dart:2662:9)
#1      _HttpClient.openUrl (dart:_http/http_impl.dart:2568:7)
#2      IOClient.send (package:http/src/io_client.dart:35:38)
#3      HttpFileService.get (package:flutter_cache_manager/src/web/file_service.dart:35:44)
#4      WebHelper._download (package:flutter_cache_manager/src/web/web_helper.dart:117:24)
#5      WebHelper._updateFile (package:flutter_cache_manager/src/web/web_helper.dart:99:28)
<asynchronous suspension>
#6      WebHelper._downloadOrAddToQueue (package:flutter_cache_manager/src/web/web_helper.dart:67:7)
<asynchronous suspension>

Image provider: CachedNetworkImageProvider("", scale: 1.0)
 Image key: CachedNetworkImageProvider("", scale: 1.0):
  CachedNetworkImageProvider("", scale: 1.0)
════════════════════════════════════════════════════════════════════════════════════════════════════

The UI shows exactly what it is suppose to though. image URL is not null image URL is null

What can I do to fix this error from showing?

Here's the code:

class ProfilePicture extends GetView<UserController> {
  const ProfilePicture({
    Key? key,
    this.enabled = false,
  }) : super(key: key);

  final bool enabled;

  double get radius => enabled ? 40.0 : 30.0;

  @override
  Widget build(BuildContext context) {
    return Obx(
      () {
        return Hero(
          tag: 'profile_hero',
          child: GestureDetector(
            child: CachedNetworkImage(
              imageUrl: controller.user?.photoURL ?? '',
              placeholder: (context, url) => Container(),
              errorWidget: (context, url, error) {
                return Stack(
                  children: [
                    CircleAvatar(
                      radius: radius,
                      backgroundColor: Get.theme.brightness == Brightness.dark
                          ? Colors.transparent
                          : Get.theme.scaffoldBackgroundColor,
                      child: Icon(Icons.person_outline_rounded,
                          size: radius * 1.5,
                          color: Get.theme.brightness == Brightness.dark
                              ? Colors.white
                              : primaryColor),
                    ),
                    Obx(
                      () => Visibility(
                        visible: controller.loading.value,
                        child: SizedBox(
                          height: radius * 2,
                          width: radius * 2,
                          child: const CircularProgressIndicator(),
                        ),
                      ),
                    ),
                  ],
                );
              },
              imageBuilder: (_, imageProvider) {
                return Stack(
                  children: [
                    CircleAvatar(
                      radius: radius,
                      backgroundImage: imageProvider,
                    ),
                    Obx(() {
                      return Visibility(
                        visible: controller.loading.value,
                        child: SizedBox(
                          height: radius * 2,
                          width: radius * 2,
                          child: const CircularProgressIndicator(
                            strokeWidth: 5,
                          ),
                        ),
                      );
                    }),
                  ],
                );
              },
            ),
            onTap: () {
              if (enabled) {
                showModalBottomSheet(
                  context: context,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(12.0),
                  ),
                  builder: (_) => const ImagePickerBottomModal(),
                );
              } else {
                Get.to(
                  const ProfileScreen(),
                  routeName: AppRoutes.routeProfile,
                  curve: Curves.fastOutSlowIn,
                  transition: Transition.downToUp,
                );
              }
            },
          ),
        );
      },
    );
  }
}

CodePudding user response:

Maybe you can do something like this. Create two CacheNetworkImage based on your url. One is for null, another is for not null.

child: (controller.user?.photoURL == null) ?
 CacheNetworkImage ( // with CircleAvatar ) : CacheNetworkImage(// with image path)

CodePudding user response:

You shouldn't be creating a CachedNetworkImage at all if you don't have an image to load.

One way to do that:

  @override
  Widget build(BuildContext context) {
    var photoURL = controller.user?.photoURL;
    var fallback = Stack(
      children: [
        CircleAvatar(...)
      ],
    );

    return Obx(
      () {
        return Hero(
          tag: 'profile_hero',
          child: GestureDetector(
            child: (photoURL == null)
              ? fallback
              : CachedNetworkImage(
                  imageUrl: photoURL,
                  placeholder: (context, url) => Container(),
                  errorWidget: (context, url, error) => fallback,
                  ...

A hacky alternative would be to just provide a non-routable URL which would be guaranteed to fail (e.g. https://0.0.0.0/).

  • Related