0Pricing
Android Academy · Aula

Carregando imagens com Coil

Carregamento assíncrono de imagens no Compose.

Carregando imagens com Coil é uma aula grátis de Android Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Android Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Android Academy inclui 4 aulas no total.

Por que você precisa de um carregador de imagens

A maioria dos aplicativos modernos exibe imagens da internet: fotos de perfil, imagens de produtos e miniaturas de artigos. Baixar e decodificar essas imagens corretamente é mais difícil do que parece.

É necessário buscar os bytes pela rede em uma thread em segundo plano, decodificá-los em um bitmap, armazená-los em cache para não fazer o download novamente e cancelar a solicitação se o usuário sair daquela área. Fazer tudo isso manualmente é propenso a erros.

Coil (Coroutine Image Loader) cuida de tudo isso para você com uma API pequena e compatível com o Compose. Nesta lição, você carregará sua primeira imagem remota.

Adicionando o Coil ao seu projeto

O Coil é distribuído como uma dependência do Gradle. Para o Jetpack Compose, você deve usar o artefato coil-compose, que fornece o componente AsyncImage.

Adicione-o ao build.gradle.kts do seu módulo. O Coil 3 é a versão principal atual e funciona em várias plataformas; a integração com o Compose é a que usamos aqui.

// build.gradle.kts (module level)
dependencies {
    implementation("io.coil-kt.coil3:coil-compose:3.0.4")
    implementation("io.coil-kt.coil3:coil-network-okhttp:3.0.4")
}

Permissão de internet

Para baixar imagens de uma URL, seu aplicativo precisa da permissão INTERNET. Esta é uma permissão normal, concedida no momento da instalação, portanto você só precisa declará-la no manifesto. Não há solicitação durante a execução.

Sem ela, todas as solicitações de rede falham com uma exceção de segurança.

<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <application ...>
        ...
    </application>
</manifest>

Sua primeira AsyncImage

A maneira mais simples de exibir uma imagem remota no Compose é usar AsyncImage. Informe um model — geralmente uma string de URL — e uma contentDescription, e o Coil fará o restante: busca em segundo plano, decodificação e exibição.

Ele usa automaticamente corrotinas vinculadas à composição, portanto a solicitação é cancelada se o componente sair da tela.

import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun Avatar() {
    AsyncImage(
        model = "https://example.com/avatar.png",
        contentDescription = "User avatar",
        modifier = Modifier.size(96.dp)
    )
}

contentScale: como a imagem se ajusta

Raramente as imagens têm exatamente o mesmo tamanho do espaço reservado pelo layout. ContentScale controla como o bitmap é redimensionado dentro de seus limites.

  • ContentScale.Crop preenche a caixa e recorta o excesso — ótimo para avatares e miniaturas.
  • ContentScale.Fit mantém a imagem inteira visível, embora possa deixar espaço vazio.
  • ContentScale.FillBounds estica a imagem para preencher o espaço, o que pode causar distorção.

Crop é a escolha mais comum para espaços de tamanho fixo.

import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun CircleAvatar(url: String) {
    AsyncImage(
        model = url,
        contentDescription = "Avatar",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .size(80.dp)
            .clip(CircleShape)
    )
}

Criando uma solicitação com ImageRequest

Passar uma string de URL é o caminho mais rápido. Para ter mais controle, crie um ImageRequest. Isso permite definir opções como transição gradual, cabeçalhos, transformações e chaves de cache.

Você precisa de um Context, que o Compose fornece por meio de LocalContext.current.

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ProductImage(url: String) {
    val context = LocalContext.current
    val request = ImageRequest.Builder(context)
        .data(url)
        .crossfade(true)
        .build()

    AsyncImage(
        model = request,
        contentDescription = "Product photo"
    )
}

Transição gradual para carregamentos suaves

Por padrão, a imagem aparece instantaneamente quando termina de carregar, o que pode parecer abrupto. crossfade(true) faz a imagem surgir gradualmente ao longo de uma animação curta.

Você também pode informar uma duração em milissegundos para tornar a transição mais lenta ou mais rápida. Esse pequeno detalhe deixa as listas muito mais refinadas.

import coil3.request.ImageRequest
import coil3.request.crossfade
import android.content.Context

fun smoothRequest(context: Context, url: String) =
    ImageRequest.Builder(context)
        .data(url)
        .crossfade(durationMillis = 300)
        .build()

Carregando de fontes diferentes

O model de AsyncImage é flexível. O Coil pode carregar vários tipos de fonte, não apenas URLs remotas:

  • Uma String ou Uri para arquivos de rede ou locais.
  • O identificador de um recurso drawable (R.drawable.logo).
  • Um File do dispositivo.
  • Um Uri de conteúdo fornecido pelo seletor de fotos.

Isso significa que o mesmo componente lida perfeitamente com imagens remotas e locais.

import android.net.Uri
import androidx.compose.runtime.Composable
import coil3.compose.AsyncImage

@Composable
fun FlexibleImage(source: Any) {
    // source can be a URL String, a Uri, a File, or a resource id
    AsyncImage(
        model = source,
        contentDescription = null
    )
}

// Examples:
// FlexibleImage("https://example.com/pic.jpg")
// FlexibleImage(Uri.parse("content://media/external/images/1"))

Reagindo ao estado do carregamento

Às vezes, você precisa saber se a imagem está carregando, foi carregada com sucesso ou falhou, para poder exibir uma interface diferente. AsyncImagePainter expõe esse estado, mas a abordagem mais simples é SubcomposeAsyncImage, que permite fornecer conteúdo para cada estado.

Na próxima lição, vamos nos aprofundar nos placeholders; aqui está a estrutura básica de um carregamento que reage ao estado.

import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import coil3.compose.SubcomposeAsyncImage

@Composable
fun StatefulImage(url: String) {
    SubcomposeAsyncImage(
        model = url,
        contentDescription = "Photo",
        loading = { CircularProgressIndicator() }
    )
}

O cancelamento vem automaticamente

Uma das maiores vantagens do Coil é o cancelamento automático. Como AsyncImage inicia sua solicitação dentro da composição, quando o componente sai da tela — por exemplo, quando uma linha sai da área visível de uma LazyColumn — a solicitação em andamento é cancelada.

Isso economiza largura de banda e CPU e evita trabalho desperdiçado. Você não precisa escrever nenhum código de cancelamento, e é por isso que o Coil funciona tão bem em listas longas.

import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage

@Composable
fun PhotoFeed(urls: List<String>) {
    LazyColumn {
        items(urls) { url ->
            AsyncImage(
                model = url,
                contentDescription = null,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(200.dp)
            )
        }
    }
}

Um cartão de imagem completo

Vamos combinar o que aprendemos: um cartão com uma imagem remota que preenche a parte superior, usa uma transição gradual e é recortada para uma altura fixa. Este é o padrão básico que você reutilizará constantemente.

import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.Text
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.unit.dp
import coil3.compose.AsyncImage
import coil3.request.ImageRequest
import coil3.request.crossfade

@Composable
fun ImageCard(title: String, imageUrl: String) {
    val context = LocalContext.current
    Card(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
        Column {
            AsyncImage(
                model = ImageRequest.Builder(context)
                    .data(imageUrl)
                    .crossfade(true)
                    .build(),
                contentDescription = title,
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxWidth().height(180.dp)
            )
            Text(text = title, modifier = Modifier.padding(16.dp))
        }
    }
}

Verificação rápida

Qual componente de coil-compose é a maneira mais simples de exibir uma imagem remota por URL no Jetpack Compose?

Recapitulação

Você carregou suas primeiras imagens remotas com o Coil. Principais aprendizados:

  • Adicione coil-compose e uma dependência de rede do OkHttp, além da permissão INTERNET.
  • AsyncImage(model = url, contentDescription = ...) é o caminho mais rápido.
  • Use ContentScale.Crop com um tamanho fixo para avatares e miniaturas.
  • Crie um ImageRequest para usar transição gradual e ter mais controle.
  • O Coil cancela automaticamente as solicitações em andamento quando os componentes saem da tela.

A seguir: como tornar o carregamento mais agradável com placeholders e estados de erro.

Perguntas Frequentes

A aula “Carregando imagens com Coil” é grátis?

Sim — o texto completo de “Carregando imagens com Coil” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Android Academy, atualize para CoddyKit PRO. O curso de Android Academy inclui 4 aulas no total.

O que vou aprender em “Carregando imagens com Coil”?

Carregamento assíncrono de imagens no Compose. Você pratica Android Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Android Academy?

Nenhuma experiência prévia é necessária. Android Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “Carregando imagens com Coil”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Android Academy?

Sim. Cada aula de Android Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Carregando imagens com Coil
  2. Marcadores e estados de erro
  3. Cache e desempenho
  4. Reproduzindo áudio e vídeo
← Voltar para Android Academy