Resumo do Capítulo 20. E/S assíncrona e de arquivo
Observação
Este livro foi publicado na primavera de 2016 e não foi atualizado desde então. Há muito no livro que permanece valioso, mas parte do material está desatualizado e alguns tópicos não estão mais totalmente corretos ou completos.
Uma interface gráfica do usuário deve responder aos eventos de entrada do usuário sequencialmente. Isso implica que todo o processamento de eventos de entrada do usuário deve ocorrer em um único thread, geralmente chamado de thread principal ou thread da interface do usuário.
Os usuários esperam que as interfaces gráficas do usuário sejam responsivas. Isso significa que um programa deve processar eventos de entrada do usuário rapidamente. Se isso não for possível, o processamento deverá ser relegado a threads secundários de execução.
Vários programas de amostra neste livro usaram a WebRequest
classe. Nessa classe, o BeginGetResponse
método inicia um thread de trabalho, que chama uma função de retorno de chamada quando é concluído. No entanto, essa função de retorno de chamada é executada no thread de trabalho, portanto, o programa deve chamar Device.BeginInvokeOnMainThread
o método para acessar a interface do usuário.
Observação
Xamarin.Forms Os programas devem ser usados HttpClient
em vez de WebRequest
acessar arquivos pela Internet. HttpClient
Suporta operações assíncronas.
Uma abordagem mais moderna para o processamento assíncrono está disponível no .NET e no C#. Isso envolve as Task
classes and Task<TResult>
e outros tipos nos System.Threading
namespaces and System.Threading.Tasks
, bem como o C# 5.0 async
e await
as palavras-chave. É nisso que este capítulo se concentra.
De retornos de chamada para aguardar
A Page
classe em si contém três métodos assíncronos para exibir caixas de alerta:
DisplayAlert
retorna umTask
objetoDisplayAlert
retorna umTask<bool>
objetoDisplayActionSheet
retorna umTask<string>
objeto
Os Task
objetos indicam que esses métodos implementam o Padrão Assíncrono Baseado em Tarefa, conhecido como TAP. Esses Task
objetos são retornados rapidamente do método. Os Task<T>
valores retornados constituem uma "promessa" de que um valor do tipo TResult
estará disponível quando a tarefa for concluída. O Task
valor retornado indica uma ação assíncrona que será concluída, mas sem nenhum valor retornado.
Em todos esses casos, o Task
é concluído quando o usuário ignora a caixa de alerta.
Um alerta com retornos de chamada
O exemplo AlertCallbacks demonstra como lidar com Task<bool>
objetos de retorno e Device.BeginInvokeOnMainThread
chamadas usando métodos de retorno de chamada.
Um alerta com lambdas
O exemplo AlertLambdas demonstra como usar funções lambda anônimas para manipulação Task
e Device.BeginInvokeOnMainThread
chamadas.
Um alerta com await
Uma abordagem mais direta envolve as async
palavras-chave e await
introduzidas no C# 5. O exemplo AlertAwait demonstra seu uso.
Um alerta sem nada
Se o método assíncrono retornar Task
em vez de Task<TResult>
, o programa não precisará usar nenhuma dessas técnicas se não precisar saber quando a tarefa assíncrona for concluída. O exemplo NothingAlert demonstra isso.
Salvando as configurações do programa de forma assíncrona
O exemplo SaveProgramChanges demonstra o uso do método de para salvar as SavePropertiesAsync
configurações do Application
programa à medida que elas são alteradas sem substituir o OnSleep
método.
Um temporizador independente de plataforma
É possível usar Task.Delay
para criar um temporizador independente de plataforma. O exemplo TaskDelayClock demonstra isso.
Entrada/saída de arquivo
Tradicionalmente, o namespace .NET System.IO
tem sido a fonte do suporte de E/S de arquivo. Embora alguns métodos neste namespace ofereçam suporte a operações assíncronas, a maioria não. O namespace também dá suporte a várias chamadas de método simples que executam funções sofisticadas de E/S de arquivo.
Boas e más notícias
Todas as plataformas suportadas pelo Xamarin.Forms armazenamento local do aplicativo de suporte — armazenamento privado para o aplicativo.
As bibliotecas Xamarin.iOS e Xamarin.Android incluem uma versão do .NET que o Xamarin adaptou expressamente para essas duas plataformas. Isso inclui classes que podem ser usadas para executar E/S de System.IO
arquivo com armazenamento local de aplicativo nessas duas plataformas.
No entanto, se você pesquisar essas System.IO
classes em uma Xamarin.Forms PCL, não as encontrará. O problema é que a Microsoft reformulou completamente a E/S de arquivos para a API do Tempo de Execução do Windows. Os programas direcionados ao Windows 8.1, Windows Phone 8.1 e Plataforma Universal do Windows não são usados System.IO
para E/S de arquivo.
Isso significa que você precisará usar o (discutido DependencyService
pela primeira vez no Capítulo 9. Chamadas de API específicas da plataforma para implementar E/S de arquivo.
Observação
As bibliotecas de classe portáteis foram substituídas por bibliotecas do .NET Standard 2.0 e o .NET Standard 2.0 dá suporte a System.IO
tipos para todas as Xamarin.Forms plataformas. Não é mais necessário usar a para a DependencyService
maioria das tarefas de E/S de arquivo. Consulte Tratamento de arquivos para Xamarin.Forms obter uma abordagem mais moderna de E/S de arquivo.
Uma primeira tentativa de E/S de arquivo multiplataforma
O exemplo TextFileTryout define uma IFileHelper
interface para E/S de arquivo e implementações dessa interface em todas as plataformas. No entanto, as implementações do Tempo de Execução do Windows não funcionam com os métodos nessa interface porque os métodos de E/S do arquivo do Tempo de Execução do Windows são assíncronos.
Acomodando E/S de arquivo do Tempo de Execução do Windows
Os programas em execução no Tempo de Execução do Windows usam classes nos Windows.Storage
namespaces e Windows.Storage.Streams
para E/S de arquivo, incluindo armazenamento local de aplicativo. Como a Microsoft determinou que qualquer operação que exija mais de 50 milissegundos deve ser assíncrona para evitar o bloqueio do thread da interface do usuário, esses métodos de E/S de arquivo são principalmente assíncronos.
O código que demonstra essa nova abordagem estará em uma biblioteca para que possa ser usado por outros aplicativos.
Bibliotecas específicas da plataforma
É vantajoso armazenar código reutilizável em bibliotecas. Isso é obviamente mais difícil quando diferentes partes do código reutilizável são para sistemas operacionais totalmente diferentes.
A Xamarin.Formssolução Book.Platform demonstra uma abordagem. Esta solução contém sete projetos diferentes:
- Xamarin.FormsBook.Platform, uma PCL normal Xamarin.Forms
- Xamarin.FormsBook.Platform.iOS, uma biblioteca de classes do iOS
- Xamarin.FormsBook.Platform.Android, uma biblioteca de classes do Android
- Xamarin.FormsBook.Platform.UWP, uma biblioteca de classes Universal do Windows
- Xamarin.FormsBook.Platform.WinRT, um projeto compartilhado para código que é comum a todas as plataformas Windows
Todos os projetos de plataforma individuais (com exceção de Xamarin.FormsBook.Platform.WinRT) têm referências a Xamarin.FormsBook.Platform. Os três projetos do Windows têm uma referência a Xamarin.FormsBook.Platform.WinRT.
Todos os projetos contêm um método estático Toolkit.Init
para garantir que a biblioteca seja carregada se não for referenciada diretamente por um projeto em uma Xamarin.Forms solução de aplicativo.
O Xamarin.Formsprojeto Book.Platform contém a nova IFileHelper
interface. Todos os métodos agora têm nomes com Async
sufixos e objetos de retorno Task
.
O Xamarin.Formsprojeto Book.Platform.WinRT contém a FileHelper
classe para o Tempo de Execução do Windows.
O Xamarin.Formsprojeto Book.Platform.iOS contém a FileHelper
classe para iOS. Esses métodos agora devem ser assíncronos. Alguns dos métodos usam as versões assíncronas dos métodos definidos em StreamWriter
e StreamReader
: WriteAsync
e ReadToEndAsync
. Outros convertem um resultado em um Task
objeto usando o FromResult
método.
O Xamarin.Formsprojeto Book.Platform.Android contém uma classe semelhante FileHelper
para Android.
O Xamarin.Formsprojeto Book.Platform também contém uma FileHelper
classe que facilita o uso do DependencyService
objeto.
Para usar essas bibliotecas, uma solução de aplicativo deve incluir todos os projetos na Xamarin.Formssolução Book.Platform e cada um dos projetos de aplicativo deve ter uma referência à biblioteca correspondente em Xamarin.FormsBook.Platform.
A solução TextFileAsync demonstra como usar as bibliotecas Book.PlatformXamarin.Forms. Cada um dos projetos tem uma chamada para Toolkit.Init
. O aplicativo usa as funções de E/S de arquivo assíncronas.
Mantendo-o em segundo plano
Os métodos em bibliotecas que fazem chamadas para vários métodos assíncronos — como os WriteFileAsync
métodos and ReadFileASync
na classe Windows Runtime FileHelper
— podem se tornar um pouco mais eficientes usando o ConfigureAwait
método para evitar a alternância de volta para o thread da interface do usuário.
Não bloqueie o thread da interface do usuário!
Às vezes, é tentador evitar o uso de ContinueWith
ou await
usando a Result
propriedade nos métodos. Isso deve ser evitado, pois pode bloquear o thread da interface do usuário ou até mesmo travar o aplicativo.
Seus próprios métodos aguardáveis
Você pode executar algum código de forma assíncrona passando-o para um dos Task.Run
métodos. Você pode chamar Task.Run
dentro de um método assíncrono que lida com parte da sobrecarga.
Os vários Task.Run
padrões são discutidos abaixo.
O conjunto básico de Mandelbrot
Para desenhar o conjunto de Mandelbrot em tempo real, o Xamarin.Forms. A biblioteca do kit de ferramentas tem uma Complex
estrutura semelhante à do System.Numerics
namespace.
O exemplo MandelbrotSet tem um CalculateMandeblotAsync
método em seu arquivo code-behind que calcula o conjunto básico de Mandelbrot em preto e branco e o usa BmpMaker
para colocá-lo em um bitmap.
Marcando o progresso
Para relatar o progresso de um método assíncrono, você pode instanciar uma Progress<T>
classe e definir seu método assíncrono para ter um argumento do tipo IProgress<T>
. Isso é demonstrado no exemplo MandelbrotProgress.
Cancelando o trabalho
Você também pode escrever um método assíncrono para ser cancelável. Você começa com uma classe chamada CancellationTokenSource
. A Token
propriedade é um valor do tipo CancellationToken
. Isso é passado para a função assíncrona. Um programa chama o Cancel
método de CancellationTokenSource
(geralmente em resposta a uma ação do usuário) para cancelar a função assíncrona.
O método assíncrono pode verificar periodicamente a IsCancellationRequested
propriedade de CancellationToken
e sair se a propriedade for true
, ou simplesmente chamar o ThrowIfCancellationRequested
método, caso em que o método termina com um OperationCancelledException
.
O exemplo MandelbrotCancellation demonstra o uso de uma função cancelável.
Um MVVM Mandelbrot
O exemplo MandelbrotXF tem uma interface do usuário mais extensa e é baseado principalmente em classes e MandelbrotModel
MandelbrotViewModel
:
Voltar para a web
A WebRequest
classe usada em alguns exemplos usa um protocolo assíncrono antiquado chamado APM ou Modelo de Programação Assíncrona. Você pode converter essa classe para o protocolo TAP moderno usando um dos FromAsync
métodos da TaskFactory
classe. O exemplo ApmToTap demonstra isso.