How to cache images from Firebase in Flutter?

3,585

This problem is actually tied to the errorWidget as seen in the issue here. The code is working if the error widget is commented out in CachedNetworkImage.

Share:
3,585
BenMilanko
Author by

BenMilanko

Updated on December 21, 2022

Comments

  • BenMilanko
    BenMilanko over 1 year

    I'm trying to access images in Firebase Storage and cache them locally on the device.

    My current attempt uses flutter_cache_manager. The documentation states:

    Most common file service will be an [HttpFileService], however one can also make something more specialized. For example you could fetch files from other apps or from local storage.

    class HttpFileService implements FileService {
      http.Client _httpClient;
      HttpFileService({http.Client httpClient}) {
        _httpClient = httpClient ?? http.Client();
      }
    
      @override
      Future<FileServiceResponse> get(String url,
          {Map<String, String> headers = const {}}) async {
        final req = http.Request('GET', Uri.parse(url));
        req.headers.addAll(headers);
        final httpResponse = await _httpClient.send(req);
    
    return HttpGetResponse(httpResponse);
    
      }
    }
    

    I've tried to extend this class to process the URL for Firebase

    class FirebaseHttpFileService extends HttpFileService {
      @override
      Future<FileServiceResponse> get(String url, {Map<String, String> headers = const {}}) async {
    
        var ref = FirebaseStorage.instance.ref().child(url);
        var _url = await ref.getDownloadURL() as String;
    
        return super.get(_url);
      }
    }
    

    And extend the BaseCacheManager using a template from the GitHub repo, replacing the file service with my new one.

    class FirebaseCacheManager extends BaseCacheManager {
      static const key = "firebaseCache";
    
      static FirebaseCacheManager _instance;
    
      factory FirebaseCacheManager() {
        if (_instance == null) {
          _instance = new FirebaseCacheManager._();
        }
        return _instance;
      }
    
      FirebaseCacheManager._() : super(key,
          maxAgeCacheObject: Duration(days: 7),
          maxNrOfCacheObjects: 20,
          fileService: FirebaseHttpFileService());
    
      Future<String> getFilePath() async {
        var directory = await getTemporaryDirectory();
        return p.join(directory.path, key);
      }
    }
    
    

    But I get the following error:

    setState() called after dispose(): _ImageState#50d41(lifecycle state: defunct, not mounted, stream: ImageStream#ac6d5(MultiFrameImageStreamCompleter#0c956, [2448×3264] @ 1.0x, 3 listeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)
    

    I can process the URL before attempting to retrieve the file but that needlessly wastes time. I've also tried to use other packages like Flutter Cache Image but it seems to crash the app after a short amount of time.

    Thanks for any pointers in the right direction!

    • Ravindra Kushwaha
      Ravindra Kushwaha almost 4 years
      Check this for the image cache stackoverflow.com/a/61813058/3946958
    • BenMilanko
      BenMilanko almost 4 years
      @ravindra-kushwaha Thank you, but I am using CachedNetworkImage already. The image URL needs to resolve through Firebase even if it has already been cached. This is why I want to implement something at the cache manager level.
    • Lee Probert
      Lee Probert over 3 years
      In your example here you are using URL to mean the StorageReference ID?
  • Lee Probert
    Lee Probert over 3 years
    Do you have a finished version of your code anywhere that I could use? I have the same requirement.
  • Lee Probert
    Lee Probert over 3 years
  • Lee Probert
    Lee Probert over 3 years
    Before I jump into this, can I use the Firebase Storage reference as the cache key? The URL could change, so I need to try and get the cached version of a file before attempting to download via the URL and then set the cache.
  • Lee Probert
    Lee Probert over 3 years
    Your Firebase Cache Manager works. Confusion with the use of URL meaning the Storage path and then also being used for the actual HTTP download URL. All good though. Thanks for this.
  • BenMilanko
    BenMilanko over 3 years
    @LeeProbert It is mine but I don't manage that repo it's Baseflow so I understand it's no longer up to date with the latest FlutterFire packages.
  • Lee Probert
    Lee Probert over 3 years
    It works fine though ... well seems to at the moment :-)
  • valley
    valley about 2 years
    @BenMilanko So when using pub.dev/packages/flutter_cache_manager_firebase i can load a file from storage by using the storage path (e.g. 'files/Tz4skw3fjgafa.pdf') with the call var file = await FirebaseCacheManager().getSingleFile('files/Tz4skw3fjgafa.pd‌​f'); and FirebaseCacheManager then converts it into a download url, downloads it and caches it with the download url?