State<List<User>?> não é delegado: top 3 erros e soluções em Kotlin

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Pânico silencioso: quando Kotlin grita que State não pode ser um delegado

\n\n

Você está escrevendo código em Kotlin, usando Jetpack Compose, tudo correndo bem. E de repente — bum! — o compilador exibe uma mensagem que faz o iniciante gelar por dentro: Type 'State<List<User>?>' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate. Parece uma sentença, mas na verdade é apenas um pedido de ajuda do seu código. Vamos entender o que ele quer dizer e como se reconciliar com ele.

\n\n

Este erro é um dos mais populares no Stack Overflow (milhares de visualizações!) e persegue desenvolvedores que estão começando a aprender propriedades delegadas em Kotlin. Neste artigo, não vamos apenas traduzir a mensagem de erro, mas mostrar três situações reais em que ela ocorre e dar soluções funcionais. Você aprenderá como usar corretamente StateFlow no Compose, como não se confundir com delegados Kotlin e por que LiveData às vezes se comporta de forma inesperada.

\n\n

O que é um delegado em Kotlin e por que State não se torna um?

\n\n

Para começar — uma rápida introdução. Propriedades delegadas em Kotlin (palavra-chave by) permitem transferir a lógica do getter e setter para um objeto separado. Por exemplo:

\n\n
var name: String by Delegates.observable("") { prop, old, new ->\n    println("$old → $new")\n}\n
\n\n

Para que um objeto possa ser um delegado, ele deve implementar os métodos getValue() e, possivelmente, setValue() com uma assinatura específica. O erro Type 'State<List<User>?>' has no method 'getValue(Nothing?, KProperty<*>)' diz exatamente isso: seu objeto do tipo State<List<User>?> não possui um método getValue adequado. O compilador não pode usá-lo como delegado.

\n\n

Agora vamos para os três cenários específicos onde esse erro aparece com mais frequência.

\n\n

Erro 1: Confusão com by e atribuição de StateFlow

\n\n

O caso mais comum é quando o desenvolvedor tenta usar by para atribuir StateFlow no ViewModel, mas faz isso incorretamente. Veja este código:

\n\n
// ❌ Erro! Não se faz assim\nclass MyViewModel : ViewModel() {\n    private val _users = MutableStateFlow<List<User>?>(null)\n    val users: StateFlow<List<User>?> by _users  // Erro!\n}\n
\n\n

Aqui, _users é um MutableStateFlow, e estamos tentando torná-lo um delegado para a propriedade users. Mas StateFlow não implementa getValue para propriedades Kotlin. Não é um delegado, é um fluxo reativo.

\n\n

Solução: use asStateFlow()

\n\n

A maneira correta não é delegar, mas transformar:

\n\n
// ✅ Correto\nclass MyViewModel : ViewModel() {\n    private val _users = MutableStateFlow<List<User>?>(null)\n    val users: StateFlow<List<User>?> = _users.asStateFlow()\n}\n
\n\n

O método asStateFlow() cria uma cópia imutável que pode ser exposta com segurança. Sem delegados, sem erros.

\n\n

Erro 2: Uso de by com LiveData no Compose

\n\n

A segunda situação mais popular é a tentativa de usar LiveData diretamente com by no Jetpack Compose. Desenvolvedores que vêm do mundo dos sistemas View estão acostumados com LiveData e tentam aplicar a mesma abordagem:

\n\n
// ❌ Erro!\n@Composable\nfun UserList(viewModel: MyViewModel) {\n    val users: List<User>? by viewModel.users  // Erro!\n    // ...\n}\n
\n\n

Aqui, viewModel.users tem o tipo LiveData<List<User>?>. E LiveData não é um delegado para propriedades do Compose. O compilador novamente exibe o mesmo erro: Type 'LiveData<List<User>?>' has

Blogs

Book Recommendations