imageflutterdartfirebase-storage

How to store image to cachednetwrok image in flutter


I have the following code where I fetch an image from firebase storage as an Image. Now, I want to store this image in my CachedNetworkImage so that I don't have to fetch it every time from the DB. Since the cachednetworkimage expects a URL and I am fetching an Image, how do I use the cachednetworkimage?

Here's my code;


  final FirebaseStorage storage = FirebaseStorage(
      app: Firestore.instance.app,
      storageBucket: 'gs://my-project.appspot.com');

  Uint8List imageBytes;
  String errorMsg;

  _MyHomePageState() {
      storage.ref().child('selfies/me2.jpg').getData(10000000).then((data) =>
                setState(() {
                  imageBytes = data;
                })
        ).catchError((e) =>
                setState(() {
                  errorMsg = e.error;
                })
        );
  }

  @override
  Widget build(BuildContext context) {
    var img = imageBytes != null ? Image.memory(
        imageBytes,
        fit: BoxFit.cover,
      ) : Text(errorMsg != null ? errorMsg : "Loading...");

    return new Scaffold(
        appBar: new AppBar(
          title: new Text(widget.title),
        ),
        body: new ListView(
          children: <Widget>[
            img,
          ],
        ));
  }
}```

Solution

  • Cached network image and Flutter cache manager

    The package Cached network image depends on another package called Flutter cache manager in order to store and retrieve image files.

    Flutter cache manager

    You need to download your image files and put them in the cache using the package. Here is an example code that gets files and their download urls from Firebase Storage and put them in the cache:

    // import the flutter_cache_manager package
    import 'package:flutter_cache_manager/flutter_cache_manager.dart';
    // ... other imports
    
    class MyCacheManager {
      Future<void> cacheImage() async {
        final FirebaseStorage storage = FirebaseStorage(
          app: Firestore.instance.app,
          storageBucket: 'gs://my-project.appspot.com',
        );
    
        final Reference ref = storage.ref().child('selfies/me2.jpg');
        
        // Get your image url
        final imageUrl = await ref.getDownloadURL();
    
        // Download your image data
        final imageBytes = await ref.getData(10000000);
    
        // Put the image file in the cache
        await DefaultCacheManager().putFile(
          imageUrl,
          imageBytes,
          fileExtension: "jpg",
        );
      }
    }
    

    Cached network image

    Next, you will use CacheNetworkImage widget as it shown in the documentation.

    // ... some code
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: CachedNetworkImage(
          imageUrl: "your_image_link_here",
          placeholder: (context, url) => CircularProgressIndicator(),
          errorWidget: (context, url, error) => Icon(Icons.error),
        ),
      );
    }
    

    If you put your image files in the cache by using Flutter cache manager, Cached network image should retrieve them from the cache directly. If your image files expire or the cache is cleared somehow, it will download and put them in the cache for you.

    Full Example

    import 'package:cached_network_image/cached_network_image.dart';
    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:firebase_storage/firebase_storage.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_cache_manager/flutter_cache_manager.dart';
    
    class MyCacheManager {
      final _storage = FirebaseStorage(
        app: FirebaseFirestore.instance.app,
        storageBucket: 'gs://my-project.appspot.com',
      );
    
      final defaultCacheManager = DefaultCacheManager();
    
      Future<String> cacheImage(String imagePath) async {
        final Reference ref = _storage.ref().child(imagePath);
    
        // Get your image url
        final imageUrl = await ref.getDownloadURL();
    
        // Check if the image file is not in the cache
        if ((await defaultCacheManager.getFileFromCache(imageUrl))?.file == null) {
          // Download your image data
          final imageBytes = await ref.getData(10000000);
    
          // Put the image file in the cache
          await defaultCacheManager.putFile(
            imageUrl,
            imageBytes,
            fileExtension: "jpg",
          );
        }
    
        // Return image download url
        return imageUrl;
      }
    }
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      String _imageUrl;
    
      @override
      void initState() {
        final myCacheManager = MyCacheManager();
    
        // Image path from Firebase Storage
        var imagePath = 'selfies/me2.jpg';
        
        // This will try to find image in the cache first
        // If it can't find anything, it will download it from Firabase storage
        myCacheManager.cacheImage(imagePath).then((String imageUrl) {
          setState(() {
            // Get image url
            _imageUrl = imageUrl;
          });
        });
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: _imageUrl != null
                ? CachedNetworkImage(
                    imageUrl: _imageUrl,
                    placeholder: (context, url) => CircularProgressIndicator(),
                    errorWidget: (context, url, error) => Icon(Icons.error),
                  )
                : CircularProgressIndicator(),
          ),
        );
      }
    }