How to Cache Network Images in Flutter

When your Flutter application is dealing with images that are fetched from the network, you can increase the performance by caching network images. This will ensure that the images do not have to be reloaded every time they are shown. Instead, they are temporarily saved on the user’s device.

Display a Regular Network Image

Before we start caching our network images, let us create a simple application that will display a network image.

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Image.network('https://picsum.photos/id/525/350/250'),
        ),
      ),
    );
  }
}

In the above code snippet, we create a simple MyApp widget that shows a centered network image using the Image.network constructor. This constructor takes the URL of the image and returns an Image widget.

The URL (https://picsum.photos/id/525/350/250) we are providing is from the picsum.photos website. This website is a placeholder image generator that provides random images with various dimensions. By specifying the id 525, we retrieve a specific image with a width of 350 pixels and a height of 250 pixels.

Now that we can display a regular network image, let us cache the same image.

Cache Network Images in Flutter

To cache network images in Flutter, we can best use the Cached Network Image package. This popular package uses the Flutter Cache Manager to store and retrieve images.

Install the Cached Network Image Package

First, we need to add the Cached Network Image package to our Flutter project. Execute the following command to install the package:

flutter pub add cached_network_image

After executing the command, let us make sure that we have the package. Open the pubspec.yaml file to check if you see the cached_network_image underneath the dependencies section:

dependencies:
  cached_network_image: ^3.3.1

Implement the Cached Network Image

Now that we have the package installed let us continue using the CachedNetworkImage widget to load and cache network images. We can do this by replacing the existing Image.network constructor with the CachedNetworkImage widget in our code.

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

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: CachedNetworkImage(
            imageUrl: 'https://picsum.photos/id/525/350/250',
          ),
        ),
      ),
    );
  }
}

In the above example, we import the cached_network_image package. After importing the package, we replace the Image.network constructor with the CachedNetworkImage image. In the CachedNetworkImage widget we set the imageUrl property to the URL of our image.

Afterward, we can restart the application and you will see that the image is loaded differently than before. This is because the CachedNetworkImage widget provides a fade animation.

If you want to disable the fade animation your can add the following property to the CachedNetworkImage widget: fadeInDuration: Duration.zero.

Improve the Cached Network Image Implementation

The CachedNetworkImage offers more properties that can help us improve the user experience. Let us go over the following example.

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

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: CachedNetworkImage(
            imageUrl: 'https://picsum.photos/id/525/350/250',
            placeholder: (BuildContext context, String url) =>
                const CircularProgressIndicator(),
            errorWidget: (BuildContext context, String url, Object error) =>
                const Icon(
              Icons.no_photography_outlined,
              size: 120,
            ),
          ),
        ),
      ),
    );
  }
}

In the above code snippet, we added the placeholder and errorWidget properties.

The placeholder property allows us to specify a widget that will be displayed while the image is being loaded. In the above example, we use a CircularProgressIndicator widget as the placeholder, which shows a loading spinner.

On the other hand, the errorWidget property allows us to specify a widget that will be displayed if the image fails to load or encounters an error. In the provided code snippet, we use an Icon widget with the Icons.no_photography_outlined icon, indicating that the image could not be found.

The placeholder and errorWidget properties, give us the control to customize the behavior of the CachedNetworkImage widget during the different stages of image loading. Of course, these are not the only available properties.

Difference Between Cached and Regular Images

After implementing the CachedNetworkImage, let us compare its performance with the regular network image.

Initial loading: Both the CachedNetworkImage and NetworkImage have similar initial loading times.

Subsequent loading: However, the true power of the CachedNetworkImage widget shows when we reload the images. The CachedNetworkImage widget loads instantly from the cache, while the regular network image needs to fetch the image again from the URL.

Conclusion

Caching network images in Flutter using the Cached Network Image package is crucial for better performance and user experience. It optimizes image loading, reduces bandwidth usage, and provides a smoother experience for users. It also provides convenient properties to control every stage of the image loading.

Tijn van den Eijnde
Tijn van den Eijnde
Articles: 37

Leave a Reply

Your email address will not be published. Required fields are marked *