Visão geral do suporte assíncrono
O C# 5 introduziu duas palavras-chave para simplificar a programação assíncrona: async e await. Essas palavras-chave permitem escrever código simples que utiliza a Biblioteca Paralela de Tarefas para executar operações de longa execução (como acesso à rede) em outro thread e acessar facilmente os resultados na conclusão. As versões mais recentes do Xamarin.iOS e Xamarin.Android suportam assíncrono e aguardam - este documento fornece explicações e um exemplo de uso da nova sintaxe com o Xamarin.
O suporte assíncrono do Xamarin é criado na base do Mono 3.0 e atualiza o perfil da API de ser uma versão compatível com dispositivos móveis do Silverlight para ser uma versão compatível com dispositivos móveis do .NET 4.5.
Visão geral
Este documento apresenta as novas palavras-chave async e await e, em seguida, apresenta alguns exemplos simples de implementação de métodos assíncronos no Xamarin.iOS e no Xamarin.Android.
Para obter uma discussão mais completa dos novos recursos assíncronos do C# 5 (incluindo muitos exemplos e diferentes cenários de uso), consulte o artigo Programação assíncrona.
O aplicativo de exemplo faz uma solicitação da Web assíncrona simples (sem bloquear o thread principal) e, em seguida, atualiza a interface do usuário com o html baixado e a contagem de caracteres.
O suporte assíncrono do Xamarin é criado na base do Mono 3.0 e atualiza o perfil da API de ser uma versão compatível com dispositivos móveis do Silverlight para ser uma versão compatível com dispositivos móveis do .NET 4.5.
Requisitos
Os recursos do C# 5 exigem o Mono 3.0 incluído no Xamarin.iOS 6.4 e no Xamarin.Android 4.8. Você será solicitado a atualizar seu Mono, Xamarin.iOS, Xamarin.Android e Xamarin.Mac para aproveitá-lo.
Usando async & await
async
e await
são novos recursos de linguagem C# que funcionam em conjunto com a Biblioteca Paralela de Tarefas para facilitar a escrita de código encadeado para executar tarefas de longa execução sem bloquear o thread principal do seu aplicativo.
async
Declaração
A async
palavra-chave é colocada em uma declaração de método (ou em um método lambda ou anônimo) para indicar que ela contém código que pode ser executado de forma assíncrona, ou seja, não bloquear o thread do chamador.
Um método marcado com async
deve conter pelo menos uma expressão ou instrução await. Se nenhuma await
instrução estiver presente no método, ele será executado de forma síncrona (o mesmo que se não houvesse modificador async
). Isso também resultará em um aviso do compilador (mas não em um erro).
Tipos de retorno
Um método assíncrono deve retornar um Task
, Task<TResult>
ou void
.
Especifique o Task
tipo de retorno se o método não retornar nenhum outro valor.
Especifique Task<TResult>
se o método precisa retornar um valor, onde TResult
é o tipo que está sendo retornado (como um int
, por exemplo).
O void
tipo de retorno é usado principalmente para manipuladores de eventos que o exigem. O código que chama métodos assíncronos de retorno de vazio não await
pode no resultado.
Parâmetros
Métodos assíncronos não podem declarar ref
ou out
parâmetros.
await
O operador await pode ser aplicado a uma Task dentro de um método marcado como async. Isso faz com que o método pare a execução nesse ponto e aguarde até que a tarefa seja concluída.
O uso de await não bloqueia o thread do chamador – em vez disso, o controle é retornado ao chamador. Isso significa que o thread de chamada não está bloqueado, portanto, por exemplo, o thread da interface do usuário não seria bloqueado ao aguardar uma tarefa.
Quando a tarefa é concluída, o método continua a execução no mesmo ponto no código. Isso inclui retornar ao escopo try de um bloco try-catch-finally (se houver um). await não pode ser usado em um bloqueio de captura ou finalmente.
Leia mais sobre aguarde.
Tratamento de exceção
As exceções que ocorrem dentro de um método assíncrono são armazenadas na tarefa e lançadas quando a tarefa é await
ed. Essas exceções podem ser capturadas e manipuladas dentro de um bloco try-catch.
Cancelamento
Os métodos assíncronos que levam muito tempo para serem concluídos devem oferecer suporte ao cancelamento. Normalmente, o cancelamento é invocado da seguinte maneira:
- Um
CancellationTokenSource
objeto é criado. - A
CancellationTokenSource.Token
instância é passada para um método assíncrono cancelável. - O cancelamento é solicitado ligando para o
CancellationTokenSource.Cancel
método.
A tarefa então se cancela e reconhece o cancelamento.
Para obter mais informações sobre o cancelamento, consulte Ajuste fino de seu aplicativo assíncrono (C#).
Exemplo
Baixe o exemplo (para iOS e Android) para ver um exemplo funcional de async
e await
em aplicativos móveis. O código de exemplo é discutido em mais detalhes nesta seção.
Escrevendo um método assíncrono
O método a seguir demonstra como codificar um async
método com uma await
tarefa ed:
public async Task<int> DownloadHomepage()
{
var httpClient = new HttpClient(); // Xamarin supports HttpClient!
Task<string> contentsTask = httpClient.GetStringAsync("https://visualstudio.microsoft.com/xamarin"); // async method!
// await! control returns to the caller and the task continues to run on another thread
string contents = await contentsTask;
ResultEditText.Text += "DownloadHomepage method continues after async call. . . . .\n";
// After contentTask completes, you can calculate the length of the string.
int exampleInt = contents.Length;
ResultEditText.Text += "Downloaded the html and found out the length.\n\n\n";
ResultEditText.Text += contents; // just dump the entire HTML
return exampleInt; // Task<TResult> returns an object of type TResult, in this case int
}
Observe estes pontos:
- A declaração de método inclui a
async
palavra-chave. - O tipo de retorno é
Task<int>
para que o código de chamada possa acessar oint
valor calculado nesse método. - A instrução return é
return exampleInt;
que é um objeto inteiro – o fato de que o método retornaTask<int>
faz parte das melhorias de linguagem.
Chamando um método assíncrono 1
Esse manipulador de eventos de clique no botão pode ser encontrado no aplicativo de exemplo do Android para chamar o método discutido acima:
GetButton.Click += async (sender, e) => {
Task<int> sizeTask = DownloadHomepage();
ResultTextView.Text = "loading...";
ResultEditText.Text = "loading...\n";
// await! control returns to the caller
var intResult = await sizeTask;
// when the Task<int> returns, the value is available and we can display on the UI
ResultTextView.Text = "Length: " + intResult ;
// "returns" void, since it's an event handler
};
Observações:
- O delegado anônimo tem o prefixo de palavra-chave assíncrona.
- O método assíncrono DownloadHomepage retorna um int Task<> que é armazenado na variável sizeTask.
- O código aguarda na variável sizeTask. Esse é o local em que o método é suspenso e o controle é retornado ao código de chamada até que a tarefa assíncrona seja concluída em seu próprio thread.
- A execução não pausa quando a tarefa é criada na primeira linha do método, apesar da tarefa ser criada lá. A palavra-chave await significa o local onde a execução está pausada.
- Quando a tarefa assíncrona é concluída, intResult é definido e a execução continua no thread original, a partir da linha de espera.
Chamando um método assíncrono 2
No aplicativo de exemplo do iOS, o exemplo é escrito de forma ligeiramente diferente para demonstrar uma abordagem alternativa. Em vez de usar um representante anônimo, este exemplo declara um async
manipulador de eventos atribuído como um manipulador de eventos regular:
GetButton.TouchUpInside += HandleTouchUpInside;
O método do manipulador de eventos é definido conforme mostrado aqui:
async void HandleTouchUpInside (object sender, EventArgs e)
{
ResultLabel.Text = "loading...";
ResultTextView.Text = "loading...\n";
// await! control returns to the caller
var intResult = await DownloadHomepage();
// when the Task<int> returns, the value is available and we can display on the UI
ResultLabel.Text = "Length: " + intResult ;
}
Alguns pontos importantes:
- O método é marcado como
async
mas retornavoid
. Isso normalmente é feito apenas para manipuladores de eventos (caso contrário, você retornaria umTask
ouTask<TResult>
). - A
await
palavra-chave noDownloadHomepage
método atribui diretamente a uma variável (intResult
), ao contrário do exemplo anterior, onde usamos uma variável intermediáriaTask<int>
para fazer referência à tarefa. Esse é o local onde o controle é retornado ao chamador até que o método assíncrono seja concluído em outro thread. - Quando o método assíncrono é concluído e retornado, a
await
execução é retomada no que significa que o resultado inteiro é retornado e, em seguida, renderizado em um widget de interface do usuário.
Resumo
Usar async e await simplifica muito o código necessário para gerar operações de longa execução em threads em segundo plano sem bloquear o thread principal. Eles também facilitam o acesso aos resultados quando a tarefa é concluída.
Este documento forneceu uma visão geral das novas palavras-chave e exemplos de linguagem para Xamarin.iOS e Xamarin.Android.
Links relacionados
- Callbacks como a declaração de nossas gerações
- MapKitSearch (iOS) (exemplo)
- Programação assíncrona
- Ajuste fino de seu aplicativo assíncrono (C#)
- Aguarde, e UI, e deadlocks! Oh meu Deus!
- Processando tarefas à medida que são concluídas)
- Padrão assíncrono baseado em tarefa (TAP)
- Assincronia em C# 5 (blog de Eric Lippert) – sobre a introdução das palavras-chave