Checking if AssetImage asset path exist

1.6k Views Asked by At

How do I load AssetImage or check if it exists? The data is coming from the api, so I cannot list all the file paths as constants.

As an example path maybe be 'assets/images/${card.imageType}.png' where card.inageType is a variable.

...
child: Image(
       height: 60.0,
       image: Utils.getImage('assets/images/card-${card.category}.png'),
       ),
...

For my getImage function, I tried 2 kinds but not working

Method 1: Using File: The existsSync method is always false. Keep in mind the await async cannot work as the Image widget is expecting not a Future

static dynamic getImage(path) {
    File f = File(path);
    return f.existsSync()
        ? FileImage(f)
        : const AssetImage('assets/images/default.png');
  }
}

Method 2: Using try catch: The exceptions is not being caught

  static AssetImage getImage(path) {
    AssetImage image;

    try {
      image = AssetImage(path);
    } catch (e) {
      image = const AssetImage('assets/images/default.png');
    }

    return image;
  }
4

There are 4 best solutions below

2
Md. Kamrul Amin On

You can not use Asset Image for images fetched from Network.

Once you get response from your api. Store the url of the image in a String variable. Usually images from API are stored in a web service.

When you have the url of the image just use NetworkImage widget, example:

SizedBox(
     width: 75,
     height: 75,
     child: userImgUrl.isEmpty
     ? const CircleAvatar(
     child: Text('Avatar'))
     : CircleAvatar(
          radius: 30,
          backgroundImage: NetworkImage(
                             userImgUrl),
                             backgroundColor: Colors.transparent),)

Think userImgUrl is the String that holds the url for the image that can be found on the internet. If image is empty just show a text inside circle avatar. If image is available from API, then show the image inside NetworkImage()

2
Zahid Tekbaş On

You can check if a file exists asynchronously with this code:

import 'dart:io';
File("path/to/file").exists() 

or checking it synchronously:

import 'dart:io';
File("path/to/file").existsSync()

Update:

isPathExists() function is called from initState.

AssetBundle is used for to obtain asset inside asset folder. You can insert anything to menubanner.png if it exists, the image will be assigned to variable and if it does not, an exception throws.


  late Image image;
  isPathExists() async {
    try {
      var assetbundle = DefaultAssetBundle.of(context);
      ByteData res = await assetbundle.load('assets/images/menubanner.png');
      var list = Uint8List.sublistView(res);
      setState(() {
        image = Image.memory(list);
      });
    } catch (exception) {
      print(exception);
    }
  }

0
Mohamed Alsaid On

You can use something like this to check if an asset exists:

// example: 'assets/check_green.png' 
Future<bool> checkIfAssetExists(String fullAssetPath) async {
  final Uint8List encoded = Utf8Codec()
      .encoder
      .convert(Uri(path: Uri.encodeFull(fullAssetPath)).path);
  // returns null if an asset is not found
  final ByteData? asset = await ServicesBinding.instance!.defaultBinaryMessenger
      .send('flutter/assets', encoded.buffer.asByteData());
  return asset != null;
}

You can run this in your initState and then use AssetImage confidently.

As for the exception not being caught, it probably means than an Error was throw which is different from Exceptions

0
Alain. Jr On

For this, I created an async method to check if the file exists, and load a default value if the file doesn't exists, and in my UI, I use a future builder.. Something like.

  static Future<ImageProvider<Object>> loadImage(
  BuildContext context, String imagePath) async {
try {
  final bundle = DefaultAssetBundle.of(context);
  await bundle.load(imagePath);
  return AssetImage(imagePath);
} catch (e) {
  return const AssetImage("assets/no_image_placeholder.png");
}}

And then in the UI,

  SizedBox(
          height: 100.0,
          width: 160.0,
          child: FutureBuilder(
            future: ProductFallbackErrorImage.loadImage(context,
                "assets/product_images/${productName.toLowerCase()}.jpg"),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Container(
                  height: 100.0,
                  width: 160.0,
                  decoration: BoxDecoration(
                    borderRadius: const BorderRadius.only(
                      topLeft: Radius.circular(8.0),
                      topRight: Radius.circular(8.0),
                    ),
                    image: DecorationImage(
                      image: snapshot.data as ImageProvider<Object>,
                      fit: BoxFit.fill,
                    ),
                  ),
                );
              } else if (snapshot.hasError) {
                'snapshot has error with value ${snapshot.error.toString()}'
                    .log();
                return Container(
                  height: 100.0,
                  width: 160.0,
                  decoration: const BoxDecoration(
                    borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(8.0),
                      topRight: Radius.circular(8.0),
                    ),
                    image: DecorationImage(
                      image: AssetImage("assets/no_image_placeholder.png"),
                      fit: BoxFit.fill,
                    ),
                  ),
                );
              } else {
                return const CircularProgressIndicator();
              }
            },
          ),
        ),

The error block will never be executed, since we are handling the level of the catch block, so i guess that can be removed.