Javid Noutash
Javid Noutash

Reputation: 2252

How to reload a FileImage in Flutter

Let's say I have an image on the device's disk and load it on the screen providing its path to a FileImage.

I edit that image and save it on the same path expecting calling the setState(() {}) function will reload it. But it doesn't.

I tried clearing the image cache by calling imageCache.clear() function and also imageProvider.evict() but no difference.

If I close that page and open it again, I see the updated images.

I assume the images that are being displayed on the screen are in the memory, if my assumption is correct, how to reload it?

Upvotes: 17

Views: 7909

Answers (8)

Susantha
Susantha

Reputation: 129

Sadly, none of the above solutions worked for me for the use case. Only solution for me was deleting the existing file, and saving the new file under the same deleted filename.

// Delete the existing file
await File(imagePath).delete();
// Copy the image to the path
await file.copy(imagePath);

Upvotes: 0

MadMurdok
MadMurdok

Reputation: 580

Just another (late) workaround

  ImageProvider loadImage(String filePath) {
    final File file = File(filePath);
    return MemoryImage(file.readAsBytesSync());
  }

Upvotes: 0

JLively
JLively

Reputation: 152

The other answers were missing step 2. Full explanation here.

  1. call imageCache.clear(); and then imageCache.clearLiveImages(); when the new image needs to be reloaded.
  2. Add a value key in the image widget to ensure the new image gets rebuilt

Image(image: FileImage(File(pathName)), key: ValueKey(File(pathName).lengthSync()))

The image should reload after.

Upvotes: 0

Mitrakov Artem
Mitrakov Artem

Reputation: 1513

This is a bit ugly workaround, but it works for me. Here we're resetting image cache + force reloading image from disk:

class _MyAppState extends State<MyApp> {
  final imageKey = GlobalKey();
  bool forceLoad = false;

  @override
  Widget build(BuildContext context) {
    final app = MaterialApp(
      home: Scaffold(
        body: forceLoad
          ? Image.memory(currentFile.readAsBytesSync(), key: imageKey)
          : Image.file  (currentFile, key: imageKey),
        floatingActionButton: FloatingActionButton(
          child: const Icon(Icons.refresh),
          onPressed: () async {
            await (imageKey.currentWidget as Image).image.evict(); // reset cache for current image
            setState(() {
              forceLoad = true;                                    // reloading current image from disk
            });
          },
        )
      )
    );
    forceLoad = false;
    return app;
  }
}

Upvotes: 0

Florin Laudat
Florin Laudat

Reputation: 129

Already tested - Adding the both image cache commands will solve the problem.

            imageCache.clear();
              imageCache.clearLiveImages();
            });

Upvotes: 3

Cristi
Cristi

Reputation: 1578

This is also working for me:

Image previewImage = Image.file(
    File(scenePreviewFilename),
);

And when pressing a button or something just evict the cached image from imageCache like this:

setState(() {
    imageCache.evict(previewImage.image, includeLive: true);
});

PS: I had some issues getting this to work(similar to the initial post) because I was generating the image in another thread and the image was loaded before it was generated, resulting in the imageCache appearing not to have an effect ... so make sure you are not in this race situation.

Upvotes: 3

Igor Kharakhordin
Igor Kharakhordin

Reputation: 9883

I know I'm a bit late, but I used this workaround:

_tmpImageFile.existsSync() ? Image.memory(
  Uint8List.fromList(_tmpImageFile.readAsBytesSync()),
  alignment: Alignment.center,
  height: 200,
  width: 200,
  fit: BoxFit.contain,
) : Container(),

Upvotes: 6

dshukertjr
dshukertjr

Reputation: 18612

Would changing the key of the Image do the trick?

Set a key to the image

Image.file(
    _imageFile,
    key: _key,
    fit: BoxFit.cover,
),

and change the key every time you change _imageFile, let's set it to timestamp for example

setState(() {
    _imageFile = newImageFile;
    _key = DateTime.now().millisecondsSinceEpoch;
});

Upvotes: 0

Related Questions