Placeholder e stati di errore
Gestisca con eleganza caricamenti ed errori
Placeholder e stati di errore è una lezione Android Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Android Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Android Academy include 4 lezioni in totale.
Il caricamento non è istantaneo
Le immagini di rete richiedono tempo. Durante questo intervallo l'interfaccia non mostra... nulla, a meno che non lo gestiate. E a volte l'immagine non arriva mai: l'URL non è valido, il server è inattivo oppure l'utente è offline.
Un'app curata mostra un placeholder durante il caricamento e un fallback quando qualcosa va storto, invece di lasciare uno spazio vuoto o causare un arresto anomalo. Coil semplifica entrambe le operazioni.
In questa lezione aggiungerete placeholder, immagini per gli errori e un'interfaccia personalizzata per ogni stato.
Un placeholder semplice
Il modo più rapido per aggiungere un placeholder consiste nel passare un drawable a AsyncImage tramite il parametro placeholder, usando painterResource. Coil lo mostra finché l'immagine reale non ha terminato il caricamento.
Usate un drawable neutro e leggero, come un riquadro grigio o la sagoma di un logo.
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage
@Composable
fun ImageWithPlaceholder(url: String) {
AsyncImage(
model = url,
contentDescription = null,
placeholder = painterResource(R.drawable.placeholder_gray)
)
}Aggiungere un'immagine per gli errori
Il parametro error mostra un drawable alternativo quando la richiesta fallisce. Esiste anche fallback, usato specificamente quando il model è null, cioè quando non c'è alcun dato da caricare.
Impostando tutti e tre, placeholder, error e fallback, coprite ogni stato visivo con pochissimo codice.
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage
@Composable
fun RobustImage(url: String?) {
AsyncImage(
model = url,
contentDescription = null,
placeholder = painterResource(R.drawable.placeholder_gray),
error = painterResource(R.drawable.image_broken),
fallback = painterResource(R.drawable.no_image)
)
}Placeholder tramite ImageRequest
Potete impostare questi stati anche direttamente nell'ImageRequest. È utile quando create la richiesta una volta e la riutilizzate, oppure quando dovete configurare contemporaneamente altre opzioni della richiesta.
Le funzioni a livello di richiesta accettano gli ID delle risorse drawable.
import android.content.Context
import coil3.request.ImageRequest
import coil3.request.crossfade
import coil3.request.error
import coil3.request.placeholder
fun buildRequest(context: Context, url: String) =
ImageRequest.Builder(context)
.data(url)
.crossfade(true)
.placeholder(R.drawable.placeholder_gray)
.error(R.drawable.image_broken)
.build()Interfaccia personalizzata con SubcomposeAsyncImage
I drawable sono sufficienti in molti casi, ma a volte potreste voler mostrare uno spinner, uno shimmer o del testo per ogni stato. SubcomposeAsyncImage consente di fornire veri composable per loading, error e success.
È più flessibile, ma anche leggermente più pesante; perciò preferite i placeholder drawable negli elenchi lunghi e riservate la subcomposition alle immagini principali.
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage
@Composable
fun HeroImage(url: String) {
SubcomposeAsyncImage(
model = url,
contentDescription = "Hero",
loading = { CircularProgressIndicator() },
error = { Text("Could not load image") }
)
}Leggere direttamente lo stato
Per avere il massimo controllo, usate l'API rememberAsyncImagePainter e ispezionatene lo state. Lo stato è un tipo sealed con i casi Loading, Success, Error ed Empty.
Questo vi consente di controllare il vostro layout, le animazioni o le analisi in base a ciò che è accaduto.
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImagePainter
import coil3.compose.rememberAsyncImagePainter
@Composable
fun StateAwareImage(url: String) {
val painter = rememberAsyncImagePainter(model = url)
val state = painter.state.collectAsState().value
when (state) {
is AsyncImagePainter.State.Loading -> { /* show spinner */ }
is AsyncImagePainter.State.Error -> { /* show error UI */ }
else -> Image(painter = painter, contentDescription = null)
}
}Mostrare un placeholder shimmer
Un modello molto diffuso è lo shimmer: un gradiente grigio animato che suggerisce l'imminente arrivo del contenuto. Potete crearne una versione semplice con un riquadro a tinta unita dietro allo stato di caricamento.
Qui usiamo SubcomposeAsyncImage con un riquadro colorato durante il caricamento. Se volete l'effetto animato, sostituite il riquadro con una libreria shimmer.
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import coil3.compose.SubcomposeAsyncImage
@Composable
fun ShimmerImage(url: String) {
SubcomposeAsyncImage(
model = url,
contentDescription = null,
loading = {
androidx.compose.foundation.layout.Box(
Modifier.fillMaxSize()
.background(MaterialTheme.colorScheme.surfaceVariant)
)
}
)
}Gestire un model null o vuoto
Cosa succede se non avete ancora un URL, per esempio per un utente senza foto profilo? Passare null come model attiva il drawable fallback, oppure error se non è stato impostato alcun fallback.
In questo modo evitate di gestire esplicitamente il valore null nel vostro codice: lasciate che Coil mostri un avatar predefinito.
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage
@Composable
fun ProfilePicture(photoUrl: String?) {
// If photoUrl is null, Coil shows the fallback default avatar.
AsyncImage(
model = photoUrl,
contentDescription = "Profile picture",
fallback = painterResource(R.drawable.default_avatar),
error = painterResource(R.drawable.default_avatar)
)
}Rilevare gli errori con un listener
A volte è necessario reagire nel codice quando un caricamento fallisce, per esempio per registrare l'errore o riprovare. ImageRequest.Builder accetta un listener con callback di successo ed errore.
Mantenete leggere queste callback: vengono eseguite nel thread principale.
import android.content.Context
import android.util.Log
import coil3.request.ImageRequest
fun loggedRequest(context: Context, url: String) =
ImageRequest.Builder(context)
.data(url)
.listener(
onError = { _, result ->
Log.e("Coil", "Load failed", result.throwable)
},
onSuccess = { _, _ ->
Log.d("Coil", "Loaded $url")
}
)
.build()Applicare tinte e filtri colore
I drawable di placeholder e di errore spesso hanno un aspetto migliore quando viene applicata una tinta coerente con il tema. Potete applicare un ColorFilter a un AsyncImage: è ideale per fallback monocromatici in stile icona che devono adattarsi alla modalità chiara e scura.
Applicate il filtro solo all'aspetto di placeholder o errore desiderato; per le foto reali, di solito è meglio non usarlo.
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import coil3.compose.AsyncImage
@Composable
fun TintedFallback(url: String?) {
AsyncImage(
model = url,
contentDescription = null,
error = painterResource(R.drawable.ic_image_placeholder),
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant)
)
}Un componente per immagini resiliente
Assembliamo un componente riutilizzabile che gestisce in modo ordinato ogni stato: sfondo di caricamento, fallback per gli errori, crossfade e ritaglio. Inseritelo in un elenco e non dovrete più preoccuparvi degli spazi vuoti.
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade
@Composable
fun ResilientImage(url: String?, size: Int = 96) {
val context = LocalContext.current
AsyncImage(
model = ImageRequest.Builder(context)
.data(url)
.crossfade(true)
.build(),
contentDescription = null,
contentScale = ContentScale.Crop,
placeholder = painterResource(R.drawable.placeholder_gray),
error = painterResource(R.drawable.image_broken),
fallback = painterResource(R.drawable.default_avatar),
modifier = Modifier.size(size.dp)
)
}Verifica rapida
Passa model = null a AsyncImage. Quale drawable mostra Coil per impostazione predefinita?
Riepilogo
Ha reso il caricamento delle immagini più fluido. Punti chiave:
placeholderviene mostrato durante il caricamento,errorin caso di errore efallbackquando il modello è null.- Può impostarli su
AsyncImageoppure suImageRequest. SubcomposeAsyncImageconsente di fornire veri composable (spinner, shimmer) per ogni stato.rememberAsyncImagePainterespone lostategrezzo per avere il pieno controllo.- Utilizzi un
listenerdella richiesta per registrare i risultati del caricamento o reagire a essi.
Prossimo argomento: caching e prestazioni, per caricare le immagini istantaneamente dalla seconda volta.
Domande Frequenti
La lezione «Placeholder e stati di errore» è gratuita?
Sì — il testo completo di «Placeholder e stati di errore» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Android Academy, passa a CoddyKit PRO. Il corso Android Academy include 4 lezioni in totale.
Cosa imparerò in «Placeholder e stati di errore»?
Gestisca con eleganza caricamenti ed errori Eserciti Android Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Android Academy?
Non è richiesta alcuna esperienza precedente. Android Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Placeholder e stati di errore»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Android Academy?
Sì. Ogni lezione Android Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Caricare immagini con Coil
- Placeholder e stati di errore
- Caching e prestazioni
- Riprodurre audio e video