Perché il caching delle immagini è importante

In molte app Flutter le immagini provengono da URL remoti: avatar, copertine, gallerie di prodotti. Caricare ogni volta queste immagini dalla rete è costoso in termini di banda, batteria e tempi di attesa. Senza una cache adeguata, scorrere una lista comporta richieste HTTP ripetute e fastidiosi sfarfallii.

Il widget Image.network di Flutter offre una cache solo in memoria, che viene svuotata alla chiusura dell'app e quando la pressione di memoria aumenta. Per una soluzione robusta, con cache anche su disco, la libreria di riferimento è cached_network_image.

Installazione

Aggiungi la dipendenza al tuo pubspec.yaml:

dependencies:
  cached_network_image: ^3.4.1

Poi esegui flutter pub get.

Utilizzo di base

Nel caso più semplice basta sostituire Image.network con CachedNetworkImage:

import 'package:cached_network_image/cached_network_image.dart';

CachedNetworkImage(
  imageUrl: 'https://example.com/foto.jpg',
  placeholder: (context, url) => const CircularProgressIndicator(),
  errorWidget: (context, url, error) => const Icon(Icons.error),
)

La prima volta l'immagine viene scaricata e salvata su disco; le volte successive viene letta direttamente dalla cache locale, in modo quasi istantaneo.

Placeholder e gestione degli errori

Uno dei vantaggi principali è la possibilità di mostrare contenuti diversi durante il caricamento e in caso di errore. Per migliorare la UX si può usare un effetto shimmer o un'immagine di fallback:

CachedNetworkImage(
  imageUrl: imageUrl,
  fadeInDuration: const Duration(milliseconds: 300),
  placeholder: (context, url) => Container(
    color: Colors.grey.shade300,
  ),
  errorWidget: (context, url, error) => Image.asset(
    'assets/placeholder.png',
    fit: BoxFit.cover,
  ),
  fit: BoxFit.cover,
)

Il parametro fadeInDuration permette una transizione morbida quando l'immagine appare, evitando l'effetto "a scatto".

Usare l'immagine come provider

A volte serve un ImageProvider invece di un widget, ad esempio per un CircleAvatar o un DecorationImage. In questo caso si usa CachedNetworkImageProvider:

CircleAvatar(
  radius: 24,
  backgroundImage: CachedNetworkImageProvider(avatarUrl),
)
Container(
  decoration: BoxDecoration(
    image: DecorationImage(
      image: CachedNetworkImageProvider(coverUrl),
      fit: BoxFit.cover,
    ),
  ),
)

Ridimensionamento e memoria

Un errore comune è caricare immagini ad alta risoluzione in spazi piccoli, sprecando memoria. Con memCacheWidth e memCacheHeight si può decodificare l'immagine a una dimensione ridotta:

CachedNetworkImage(
  imageUrl: thumbnailUrl,
  memCacheWidth: 200,
  memCacheHeight: 200,
  fit: BoxFit.cover,
)

Questo riduce significativamente il consumo di RAM, soprattutto in liste e griglie con molte immagini.

Configurare la cache

Dietro le quinte, cached_network_image usa il pacchetto flutter_cache_manager. È possibile personalizzare durata e dimensione massima della cache creando un cache manager dedicato:

import 'package:flutter_cache_manager/flutter_cache_manager.dart';

class CustomCacheManager {
  static const key = 'customCache';

  static final instance = CacheManager(
    Config(
      key,
      stalePeriod: const Duration(days: 7),
      maxNrOfCacheObjects: 200,
    ),
  );
}

E poi passarlo al widget:

CachedNetworkImage(
  imageUrl: imageUrl,
  cacheManager: CustomCacheManager.instance,
)

In questo modo le immagini vengono rimosse dopo 7 giorni e non si superano mai i 200 file in cache.

Svuotare la cache

È utile fornire all'utente un'opzione per liberare spazio, oppure forzare il refresh di un'immagine aggiornata:

// Svuota tutta la cache
await DefaultCacheManager().emptyCache();

// Rimuove una singola immagine
await DefaultCacheManager().removeFile(imageUrl);

Best practice

  • Usa sempre placeholder ed errorWidget per evitare schermate vuote o crash visivi.
  • Imposta memCacheWidth/memCacheHeight nelle liste per limitare il consumo di memoria.
  • Definisci un stalePeriod coerente con la frequenza di aggiornamento dei tuoi contenuti.
  • Per immagini che cambiano spesso allo stesso URL, valuta di aggiungere un parametro di versione o di rimuovere il file dalla cache.
  • Combina con BoxFit.cover e un Container di sfondo per un layout stabile durante il caricamento.

Conclusione

cached_network_image è una libreria matura e semplice da integrare che migliora sensibilmente performance e percezione di fluidità della tua app. Con poche righe di codice ottieni cache su disco, placeholder, gestione errori e controllo fine sul consumo di memoria: un alleato indispensabile in qualsiasi app che mostri immagini di rete.