flutter_cached_network_image icon indicating copy to clipboard operation
flutter_cached_network_image copied to clipboard

After setting memCacheHeight, .evict() is invalid

Open maskletter opened this issue 4 years ago • 15 comments

code

CachedNetworkImage(
              memCacheHeight: 200,
              imageUrl:
                  'https://img0.baidu.com/it/u=3863723642,1799521238&fm=26&fmt=auto&gp=0.jpg');

    ImageCache? imageCache = PaintingBinding.instance?.imageCache;
    print(imageCache?.currentSize);
    print(imageCache?.currentSizeBytes);
//-------------
CachedNetworkImageProvider(
      "https://img0.baidu.com/it/u=3863723642,1799521238&fm=26&fmt=auto&gp=0.jpg",
).evict();
    ImageCache? imageCache = PaintingBinding.instance?.imageCache;
    print(imageCache?.currentSize);
    print(imageCache?.currentSizeBytes);

error

The picture still exists in memory

version

cached_network_image: ^3.1.0 Flutter 2.2.3 • channel stable • https://github.com/flutter/flutter.git Framework • revision f4abaa0735 (9 weeks ago) • 2021-07-01 12:46:11 -0700 Engine • revision 241c87ad80 Tools • Dart 2.13.4

maskletter avatar Sep 01 '21 05:09 maskletter

That's correct. You will get a different ImageProvider here. For example when you have large and small versions of the same image you might want to evict the large image all the time after it is no longer needed, but you can keep the small versions in memory.

Could you try:

CachedNetworkImage(
              memCacheHeight: 200,
              imageUrl:
                  'https://img0.baidu.com/it/u=3863723642,1799521238&fm=26&fmt=auto&gp=0.jpg');

CachedNetworkImage(
              memCacheHeight: 200,
              imageUrl:
                  'https://img0.baidu.com/it/u=3863723642,1799521238&fm=26&fmt=auto&gp=0.jpg',
).evict();

If that doesn't work please reopen the issue and I'll have a closer look.

renefloor avatar Sep 01 '21 06:09 renefloor

I tried it,The only key of obtainKey has been used in the ResizeImage component to clean up the memory. Is there any way for CachedNetworkImage to obtain the obtainKey?

maskletter avatar Sep 01 '21 06:09 maskletter

ResizeImage aa = ResizeImage(NetworkImage(imgUrl), width: 200);
    aa.obtainKey(ImageConfiguration.empty).then((value) {
      ImageCache? imageCache = PaintingBinding.instance?.imageCache;
      imageCache?.evict(value);
    });

Is there any way for CachedNetworkImage to obtain acquireKey?

maskletter avatar Sep 01 '21 06:09 maskletter

Hmm of course, the ResizeImage is in between. I think the same trick should work as well:

ResizeImage aa = ResizeImage(CachedNetworkImageProvider(imgUrl), height: 200);
    aa.obtainKey(ImageConfiguration.empty).then((value) {
      ImageCache? imageCache = PaintingBinding.instance?.imageCache;
      imageCache?.evict(value);
    });

renefloor avatar Sep 01 '21 06:09 renefloor

Thanks, I know how to deal with it

maskletter avatar Sep 01 '21 06:09 maskletter

@maskletter @renefloor @bounty1342 I encountered the same problem and submitted a PR #676 which may not be very good. Please pay attention to it and give some suggestions. Thank you very much.

weiminghuaa avatar Dec 24 '21 08:12 weiminghuaa

Hi @renefloor, I have close PR #676 because I think it a bug in ResizeImage. I rewrite ResizeImage for get ResizeImageKey. And I will add some code in error widget build to evict pending cache when something error. I don't know if this problem has better solution?

CachedNetworkImage(
            memCacheHeight: null,
            memCacheWidth: 375,
            progressIndicatorBuilder: (context, url, progress) =>
                Text("progress:${progress.progress}"),
            errorWidget: (context, url, object) {
              // follow #648 Proactively clear the pending cache
              ResizeImage aa =
                  ResizeImage(CachedNetworkImageProvider(imgUrl), width: 375);
              aa.obtainKey(ImageConfiguration.empty).then((value) {
                ImageCache? imageCache = PaintingBinding.instance?.imageCache;
                imageCache?.evict(value);
              });
              return Text("error");
            },
            imageUrl: imgUrl),

weiminghuaa avatar Dec 29 '21 08:12 weiminghuaa

At one point, cacheNetwork image call octoImage wrap in a ResizeImage, it's where the imageprovider reference in lost. I'm on mobile now but can give source later today.

bounty1342 avatar Dec 29 '21 09:12 bounty1342

Hi @bounty1342, I have see that, I found it a bug in ResizeImage. If I use Image.network, it's also can't evict pending image cache, because the key is not right which flutter provider. In pending image cache, the key is ResizeImageKey, and it's private we can't get it. Only one way to get it by create a new ResizeImage.

// this code also has the same evict problem
Image(
     image: ResizeImage(NetworkImage(imgUrl), width: 375),
),

weiminghuaa avatar Dec 29 '21 09:12 weiminghuaa

I don't know if this problem has better solution?

@weiminghuaa I don't know either. I have to take some time to look into it, but I can imagine it not working due to the wrapping of the ResizeImage.

// this code also has the same evict problem
Image(
     image: ResizeImage(NetworkImage(imgUrl), width: 375),
),

Can you evict this image by calling: ResizeImage(NetworkImage(imgUrl), width: 375).evict()?

renefloor avatar Dec 29 '21 13:12 renefloor

Can you evict this image by calling: ResizeImage(NetworkImage(imgUrl), width: 375).evict()?

@renefloor Yes, it's ok.

weiminghuaa avatar Dec 30 '21 02:12 weiminghuaa

So we can change this:

  static Future evictFromCache(
    String url, {
    String? cacheKey,
    BaseCacheManager? cacheManager,
    double scale = 1.0,
  }) async {
    cacheManager = cacheManager ?? DefaultCacheManager();
    await cacheManager.removeFile(cacheKey ?? url);
    return CachedNetworkImageProvider(url, scale: scale).evict();
  }

to this:

  static Future evictFromCache(
    String url, {
    String? cacheKey,
    int? memCacheWidth,
    int? memCacheHeight,
    BaseCacheManager? cacheManager,
    double scale = 1.0,
  }) async {
    cacheManager = cacheManager ?? DefaultCacheManager();
    await cacheManager.removeFile(cacheKey ?? url);
    final imageProvider = ResizeImage.resizeIfNeeded(
          memCacheWidth,
          memCacheHeight,
          CachedNetworkImageProvider(url, scale: scale),
        );
    return imageProvider.evict();
  }

renefloor avatar Dec 30 '21 10:12 renefloor

No, I tracked the source code and found a problem here. If network image load error when no network connect, can't evict the key. So next time it's can't retry load image even though nework is ok. Because the pending image cache not evict the image key.

Stream<ui.Codec> _loadAsync(
    image_provider.CachedNetworkImageProvider key,
    StreamController<ImageChunkEvent> chunkEvents,
    DecoderCallback decode,
  ) {
    assert(key == this);
    return ImageLoader().loadAsync(
      url,
      cacheKey,
      chunkEvents,
      decode,
      cacheManager ?? DefaultCacheManager(),
      maxHeight,
      maxWidth,
      headers,
      errorListener,
      imageRenderMethodForWeb,
      () => PaintingBinding.instance?.imageCache?.evict(key),
    );
  }

weiminghuaa avatar Dec 30 '21 12:12 weiminghuaa

Ah you're talking about a failed image, that's interesting. The OP talked about evict in general, then my piece of code already helped.

It's a bit hacky, but I think this should work:

Stream<ui.Codec> _loadAsync(
    image_provider.CachedNetworkImageProvider key,
    StreamController<ImageChunkEvent> chunkEvents,
    DecoderCallback decode,
  ) {
    assert(key == this);
    return ImageLoader().loadAsync(
      url,
      cacheKey,
      chunkEvents,
      decode,
      cacheManager ?? DefaultCacheManager(),
      maxHeight,
      maxWidth,
      headers,
      errorListener,
      imageRenderMethodForWeb,
      () => PaintingBinding.instance?.imageCache?.evict(ResizeImage.resizeIfNeeded(
          memCacheWidth,
          memCacheHeight,
          CachedNetworkImageProvider(url, cacheKey: cacheKey, scale: scale),
        )),
    );
  }

Edit: nvm, we don't have that information here of course...

renefloor avatar Dec 30 '21 12:12 renefloor

Yes,no memCacheWidth, memCacheHeight

weiminghuaa avatar Dec 31 '21 03:12 weiminghuaa