Elementy zastępcze i stany błędów
Elegancka obsługa wczytywania i niepowodzeń
Elementy zastępcze i stany błędów to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.
Ładowanie nie jest natychmiastowe
Obrazy z sieci potrzebują czasu. W tym czasie interfejs wyświetla… nic, chyba że odpowiednio to obsłużysz. Czasami obraz w ogóle nie dociera: adres URL jest nieprawidłowy, serwer nie działa albo użytkownik jest offline.
Dopracowana aplikacja wyświetla element zastępczy podczas ładowania oraz element awaryjny w razie błędu, zamiast pustego miejsca lub awarii. Coil ułatwia oba rozwiązania.
W tej lekcji dodasz elementy zastępcze, obrazy wyświetlane w razie błędu oraz niestandardowy interfejs dla poszczególnych stanów.
Prosty element zastępczy
Najszybszym sposobem dodania elementu zastępczego jest przekazanie drawable do AsyncImage za pomocą parametru placeholder i funkcji painterResource. Coil wyświetla go do czasu zakończenia ładowania właściwego obrazu.
Użyj neutralnego, lekkiego drawable, na przykład szarego pola lub sylwetki 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)
)
}Dodawanie obrazu w razie błędu
Parametr error wyświetla awaryjny drawable, gdy żądanie się nie powiedzie. Dostępny jest również parametr fallback, używany konkretnie wtedy, gdy model ma wartość null, czyli nie ma żadnych danych do załadowania.
Ustawienie wszystkich trzech parametrów — placeholder, error i fallback — obejmuje każdy stan wizualny niemal bez dodatkowego kodu.
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)
)
}Element zastępczy przez ImageRequest
Te stany można również ustawić bezpośrednio w obiekcie ImageRequest. Jest to przydatne, gdy budujesz żądanie raz i używasz go ponownie lub gdy jednocześnie potrzebujesz innych opcji żądania.
Funkcje dostępne na poziomie żądania przyjmują identyfikatory zasobów 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()Niestandardowy interfejs z SubcomposeAsyncImage
Drawable sprawdza się dobrze, ale czasami potrzebny jest dla każdego stanu spinner, shimmer lub tekst. SubcomposeAsyncImage pozwala dostarczyć rzeczywiste composable dla stanów loading, error i success.
To rozwiązanie jest bardziej elastyczne, ale nieco cięższe, dlatego w przypadku długich list lepiej używać drawable jako elementów zastępczych, a subkompozycję pozostawić dla obrazów głównych.
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") }
)
}Bezpośrednie odczytywanie stanu
Aby uzyskać pełną kontrolę, użyj API rememberAsyncImagePainter i sprawdzaj jego state. Stan jest typem zapieczętowanym, który obejmuje przypadki Loading, Success, Error i Empty.
Pozwala to sterować własnym układem, animacjami lub analityką na podstawie tego, co się wydarzyło.
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)
}
}Wyświetlanie elementu zastępczego shimmer
Popularnym wzorcem jest shimmer — animowany szary gradient sugerujący, że zawartość jest w trakcie ładowania. Prostą wersję można zbudować, umieszczając jednokolorowe pole za stanem ładowania.
W tym przykładzie podczas ładowania używamy SubcomposeAsyncImage z polem o określonym odcieniu. Jeśli chcesz uzyskać efekt animacji, zamień pole na bibliotekę 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)
)
}
)
}Obsługa pustego lub null modelu
Co zrobić, gdy nie masz jeszcze adresu URL, na przykład gdy użytkownik nie ma zdjęcia profilowego? Przekazanie null jako modelu uruchamia drawable fallback (lub error, jeśli nie ustawiono fallback).
Dzięki temu nie trzeba osobno obsługiwać wartości null we własnym kodzie — pozwól Coil wyświetlić domyślny awatar.
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)
)
}Reagowanie na błędy za pomocą listenera
Czasami trzeba zareagować w kodzie na nieudane ładowanie, na przykład zapisać błąd w logu lub ponowić próbę. ImageRequest.Builder przyjmuje listener z wywołaniami zwrotnymi sukcesu i błędu.
Te wywołania zwrotne powinny wykonywać niewiele pracy, ponieważ działają w głównym wątku.
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()Barwienie i filtry kolorów
Elementy zastępcze i drawable wyświetlane w razie błędu często najlepiej wyglądają po zabarwieniu zgodnie z motywem. Do AsyncImage można zastosować ColorFilter, co świetnie sprawdza się w przypadku monochromatycznych ikon awaryjnych, które powinny dopasowywać się do jasnego i ciemnego motywu.
Filtr stosuj tylko do wybranego wyglądu elementu zastępczego lub awaryjnego; w przypadku prawdziwych zdjęć zwykle należy go pominąć.
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)
)
}Odporna na błędy komponentowa obsługa obrazu
Złóżmy wielokrotnego użytku komponent, który poprawnie obsługuje każdy stan: tło podczas ładowania, awaryjny obraz, crossfade i przycinanie. Dodaj go do listy i przestań martwić się pustymi miejscami.
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)
)
}Szybkie sprawdzenie
Przekazują Państwo model = null do AsyncImage. Który drawable Coil wyświetla domyślnie?
Podsumowanie
Udało się Państwu obsłużyć ładowanie obrazów w elegancki sposób. Najważniejsze informacje:
placeholderjest wyświetlany podczas ładowania,errorw razie błędu, afallback, gdy model ma wartość null.- Można je ustawić w
AsyncImagelub wImageRequest. SubcomposeAsyncImagepozwala dostarczać rzeczywiste composable (spinner, shimmer) dla poszczególnych stanów.rememberAsyncImagePainterudostępnia surowystate, zapewniając pełną kontrolę.- Za pomocą
listenerżądania można rejestrować wyniki ładowania lub na nie reagować.
Następnie: buforowanie i wydajność, aby obrazy ładowały się natychmiast przy drugim wyświetleniu.
Ucz się Kotlin dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 36
- Lekcje
- 152
Często zadawane pytania
Czy lekcja „Elementy zastępcze i stany błędów” jest bezpłatna?
Tak — pełny tekst „Elementy zastępcze i stany błędów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Elementy zastępcze i stany błędów”?
Elegancka obsługa wczytywania i niepowodzeń Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Android Academy?
Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Elementy zastępcze i stany błędów”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?
Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wczytywanie obrazów za pomocą Coil
- Elementy zastępcze i stany błędów
- Buforowanie i wydajność
- Odtwarzanie dźwięku i obrazu