ActivityResultLauncher é um componente da API Activity Result do Android, apresentado na versão Activity 1.2.0 da biblioteca androidx.activity. Ele substitui os métodos obsoletos startActivityForResult e onActivityResult, que faziam parte do Android SDK desde sua criação. De acordo com Android Developers (2024), a nova API elimina os problemas de acoplamento forte com Activity e a falta de segurança de tipos. ActivityResultLauncher é registrado antecipadamente e usa um Contract para tipagem estrita dos dados de entrada e saída.
Pontos principais
ActivityResultLauncher é uma classe do pacote androidx.activity.result que fornece um mecanismo type-safe para iniciar uma Activity e receber um resultado. O launcher é criado através do método registerForActivityResult, que aceita dois parâmetros: Contract (descreve os tipos de entrada e saída) e ActivityResultCallback (manipulador de resultado). Após o registro, o launcher está pronto para ser chamado através do método launch.
A diferença chave da API antiga é a separação do registro e da execução. O registro é realizado na fase de inicialização (Activity.onCreate ou Fragment.onCreate), o callback é vinculado ao launcher uma vez e tem a garantia de ser executado quando o resultado retornar. Isso elimina o problema de onActivityResult ser executado em uma ordem inesperada ou em uma Activity destruída.
ActivityResultLauncher suporta todos os cenários que anteriormente eram tratados via onActivityResult: iniciar a câmera, galeria, solicitar contatos, permissões e Activities personalizadas. Além disso, a API é extensível: os desenvolvedores podem criar Contracts personalizados para cenários específicos de troca de dados entre Activities.
startActivityForResult fez parte do Android SDK desde API Level 1 (2008) e continuou sendo a principal forma de obter um resultado de uma Activity por mais de 12 anos. No entanto, este método tinha deficiências fundamentais que o Google resolveu no Activity Result API. Vamos ver os principais problemas e como a nova API os soluciona.
O método startActivityForResult está vinculado a Activity e Fragment através de requestCode — um número inteiro arbitrário passado para onActivityResult. O desenvolvedor manualmente associava o código à operação iniciada, levando a erros na reutilização de código e herança. ActivityResultLauncher elimina completamente requestCode: o callback é vinculado a um launcher específico no momento do registro e só é invocado para ele.
Durante mudanças de configuração (rotação de tela, mudança de idioma), a Activity era recriada e onActivityResult podia não ser executado — o callback era perdido. O Activity Result API salva e restaura automaticamente o estado do launcher através do SavedStateRegistry, garantindo que o resultado seja recebido mesmo após a recriação da Activity.
A API antiga passava o resultado através de Intent com Bundle, onde chaves e tipos de dados não eram verificados pelo compilador. O Activity Result API usa Contract — uma interface genérica que define o tipo de dados de entrada (I) e o tipo de resultado (O). Erros de incompatibilidade de tipos são detectados em tempo de compilação, não em tempo de execução.
| Característica | startActivityForResult | ActivityResultLauncher |
|---|---|---|
| RequestCode | Gerenciamento manual necessário | Automático, não necessário |
| Segurança de tipos | Não | Contract genérico |
| Salvar ao girar | Perdido | SavedStateRegistry |
| API mínima | API Level 1 | Activity 1.2.0 |
| Uso no Compose | Não suportado | rememberLauncherForActivityResult |
Contract é a interface ActivityResultContract<I, O>, que define como iniciar uma Activity e como interpretar o resultado. O Google fornece um conjunto de contratos integrados para cenários típicos que cobrem a maioria das necessidades do desenvolvedor.
StartIntentSenderForResult — um contrato básico para iniciar IntentSender. Usado em cenários de sistema, por exemplo ao autorizar via Google Sign-In ou fazer pagamentos via Google Pay. O parâmetro de entrada é PendingIntent, a saída é ActivityResult com código e Intent.
RequestMultiplePermissions — um contrato para solicitar várias permissões simultaneamente no Android 6.0+. O parâmetro de entrada é um array de String com nomes de permissões, a saída é Map<String, Boolean> com o resultado de cada solicitação. Anteriormente isso exigia análise manual em onRequestPermissionsResult com correspondência de códigos de solicitação.
TakePicture — um contrato para tirar uma foto através da câmera do sistema. A entrada é um Uri para salvar a imagem, a saída é Boolean (sucesso). TakeVideo funciona de forma semelhante com vídeo. Esses contratos substituem o obsoleto MediaStore.ACTION_IMAGE_CAPTURE com comportamento instável em diferentes dispositivos.
GetContent — um contrato para selecionar conteúdo através do seletor do sistema. A entrada é um tipo MIME (por exemplo, image/*), a saída é um Uri do arquivo selecionado. OpenDocument difere por suportar seleção múltipla e filtragem por tipos de documento. Ambos os contratos funcionam através de SAF (Storage Access Framework).
CreateDocument — um contrato para criar um novo documento através do diálogo do sistema. O usuário escolhe um nome e uma pasta, o sistema retorna um Uri para escrita. OpenDocumentTree fornece acesso a um diretório completo — o usuário seleciona uma pasta e o aplicativo recebe um tree-uri para ler e escrever todos os arquivos dentro dela.
O padrão básico para usar ActivityResultLauncher no Android clássico consiste em duas etapas: registro através de registerForActivityResult na inicialização e chamada de launch em resposta a uma ação do usuário. Vamos ver um exemplo típico de seleção de uma imagem da galeria.
Registre o launcher no onCreate da Activity — isso garante que o callback esteja pronto antes de qualquer chamada possível. Nunca registre um launcher imediatamente antes de executá-lo — isso viola o contrato da API e pode levar à perda do resultado ao recriar a Activity.
class MainActivity : AppCompatActivity() {
private val pickImageLauncher =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
uri?.let { binding.imageView.setImageURI(it) }
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
pickImageLauncher.launch("image/*")
}
}
Em um Fragment, o registro é feito em onCreate, onAttach ou inicialização em onCreateView. O FragmentActivity passa o launcher através da Activity pai, então o resultado é processado dentro do Fragment, não na Activity. Isso melhora o encapsulamento em comparação com onActivityResult, onde todos os resultados de todos os Fragments eram reunidos em um único método da Activity.
class ProfileFragment : Fragment() {
private val cameraLauncher =
registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
if (success) { updateProfilePhoto() }
}
fun takePhoto(photoUri: Uri) {
cameraLauncher.launch(photoUri)
}
}
Jetpack Compose fornece uma função composable especial para Activity Result API — rememberLauncherForActivityResult. Ao contrário da abordagem clássica, no Compose o launcher é criado como um objeto vinculado ao ciclo de vida do composable através de remember. Isso permite usar o Activity Result API completamente em estilo declarativo sem acesso direto a Activity ou Fragment.
rememberLauncherForActivityResult aceita um Contract e um callback, retornando um ActivityResultLauncher. O launcher é preservado durante a recomposição e automaticamente limpo ao sair da composição. A chamada de launch ocorre em resposta a um evento — por exemplo, um clique em botão ou mudança de estado.
@Composable
fun PhotoPicker() {
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
ActivityResultContracts.GetContent()
) { uri -> handleImage(uri) }
Button(onClick = { launcher.launch("image/*") }) {
Text("Escolher foto")
}
}
Solicitações de permissão no Compose também são feitas através de rememberLauncherForActivityResult com o contrato RequestPermission ou RequestMultiplePermissions. O Google recomenda usar accompanist-permissions, mas internamente ele também usa o Activity Result API. Para controlar o estado das permissões, é conveniente armazenar o estado em remember ou ViewModel.
Activity Result API eliminou muitos problemas da abordagem antiga, mas o uso inadequado pode levar a novos tipos de erros. Vamos ver os problemas mais comuns e como evitá-los.
O registro do launcher deve ser feito durante a inicialização do componente — no onCreate da Activity ou inicializador do Fragment. Se você registrar o launcher dentro de uma lambda, callback ou corrotina, ao recriar a Activity o registro pode ser feito novamente e o launcher antigo perderá a conexão com o resultado.
Cada launcher recebe uma chave única para salvar o estado. Se você registrar dois launchers com o mesmo Contract em um componente, o SavedStateRegistry pode sobrescrever o estado de um com o do outro. O Android Studio avisa sobre isso através da regra lint UnnecessaryRegisterForActivityResult, mas é melhor controlar a exclusividade manualmente.
O usuário pode cancelar a ação — pressionar o botão voltar do sistema, minimizar o aplicativo ou mudar para outro aplicativo. Neste caso, o callback receberá null ou ActivityResult com RESULT_CANCELED. Sempre verifique se o resultado é null antes de usá-lo para evitar NullPointerException.
Se seu aplicativo inicia frequentemente cenários semelhantes — por exemplo, selecionar um contato e retornar nome e telefone — crie um Contract personalizado. Isso melhora a legibilidade do código e permite alterações centralizadas na lógica de inicialização e tratamento de resultados.
class PickContactContract : ActivityResultContract<Void, ContactData?>() {
override fun createIntent(context: Context, input: Void?) =
Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE)
override fun parseResult(resultCode: Int, intent: Intent?) =
intent?.data?.let { queryContact(it) }
}
Perguntas frequentes
Não — ActivityResultLauncher requer um contexto de Activity ou Fragment para registro. Use ViewModel apenas para armazenar estado, e crie o launcher na Activity ou Fragment e passe o resultado para o ViewModel.
Activity Result API está disponível a partir da biblioteca activity-ktx 1.2.0. O SDK mínimo é API Level 14 (Android 4.0), mas a maioria dos contratos funciona apenas em API Level 19+.
Uma chamada repetida de launch antes da primeira operação terminar será ignorada. O Activity Result API não suporta execuções paralelas — aguarde o callback da primeira operação antes de fazer uma nova chamada.
A migração é feita substituindo a chamada startActivityForResult por registerForActivityResult com o Contract apropriado. Remova onActivityResult e manipule o resultado no callback do launcher. O Google fornece um guia de migração na documentação do Android Developers.
Sim, muitas bibliotecas suportam integração através de ActivityResultContracts. Por exemplo, ML Kit Barcode Scanner usa StartIntentSenderForResult para iniciar o scanner. Verifique a documentação da biblioteca específica.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também