Simplify image caching in Flutter with this package

Simplify image caching in Flutter with this package

If your application showcases one or more images that are hosted on an internet server, it is generally wise to cache these images temporarily. This will prevent the need to repeatedly download them as the user navigates through your application.

For instance, consider a social network where users can browse their news feed, view post details, and save posts as favorites. Now, let's consider the implications of having to download the same image repeatedly. If the user had to download the thumbnail every time they scrolled through the post list, accessed post details, or viewed their favorites list, it would result in unnecessary network resource usage and server overload. Moreover, the user would have to wait for the image to download each time, leading to a frustrating experience.

📽 Video version available on YouTube and Odysee

For this reason, Flutter has a built-in mechanism that enables the management of files in a specific directory designed for temporary files. The primary purpose of this directory is to store temporary data, which can be regenerated by the application if they are deleted. The goal of this directory is to improve the overall performance or to enhance the user experience in some way. Nevertheless, managing these files can be dull and tedious. To simplify this process, we have the cached_network_image package, which abstracts us from cache memory management.

This package will take care of downloading the image the first time, saving it in the cache, and will retrieve it from there if the same image is requested again.

How to cache an Image from a URL in Flutter

Let's create a sample application to see how it works:

flutter create cached_network_image_sample

Now let's install cached_network_image:

flutter pub add cached_network_image

As an example, I will take a real photo of the galaxy. This photo is quite large, replace the contents of lib/main.dart with the following:

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const App());
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'cached_network_image sample',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MainScreen(),
    );
  }
}

class MainScreen extends StatelessWidget {
  static const _url = 'https://cdn.eso.org/images/large/eso1031b.jpg';

  const MainScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('cached_network_image sample'),
      ),
      body: Center(
        child: Container(
          padding: const EdgeInsets.only(
            left: 24.0,
            right: 24.0,
          ),
          child: CachedNetworkImage(
            imageUrl: _url,
          ),
        ),
      ),
    );
  }
}

The first time CachedNetworkImage requests to render this image it will download it from the internet and save it, and from then on it will retrieve it from the cache. We can also set a specific loading widget via the progressIndicatorBuilder parameter:

// [...]
child: CachedNetworkImage(
  imageUrl: _url,
  progressIndicatorBuilder: (context, url, progress) =>
      const CircularProgressIndicator(),
),
// [...]

It is also possible to define a widget that will be displayed in case the image load fails for any reason:

child: CachedNetworkImage(
  imageUrl: _url,
  progressIndicatorBuilder: (context, url, progress) =>
  const CircularProgressIndicator(),
  errorWidget: (context, url, error) => const Center(
    child: Icon(
      Icons.error,
      color: Colors.red,
    ),
  ),
),

Try to alter the URL of the image to break it, you will see that the indicated widget is displayed instead.

As you can see, this easy-to-use package eliminates the need to store images downloaded from the internet, thus enhancing the usability and experience of our application.

I hope this article has been useful to you, see you in the next one.

Happy coding!

Did you find this article valuable?

Support David Serrano by becoming a sponsor. Any amount is appreciated!