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 a 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 deve ser relegado a threads secundários de execução.
Vários programas de exemplo 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 ela é concluída. 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 processamento assíncrono está disponível em .NET e C#. Isso envolve as Task
classes e Task<TResult>
e outros tipos nos System.Threading
namespaces e System.Threading.Tasks
, bem como o C# 5.0 async
e await
palavras-chave. É nisso que este capítulo se concentra.
De retornos de chamada a espera
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 de retorno constituem uma "promessa" de que um valor de tipo TResult
estará disponível quando a tarefa for concluída. O Task
valor de retorno 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 descarta a caixa de alerta.
Um alerta com retornos de chamada
O exemplo AlertCallbacks demonstra como manipular 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 será concluída. O exemplo NothingAlert demonstra isso.
Salvando configurações do programa de forma assíncrona
O exemplo SaveProgramChanges demonstra o uso do SavePropertiesAsync
método de para salvar as configurações do Application
programa como eles mudam 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 arquivos
Tradicionalmente, o namespace .NET System.IO
tem sido a fonte do suporte de E/S de arquivo. Embora alguns métodos nesse namespace ofereçam suporte a operações assíncronas, a maioria não. O namespace também oferece 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 oferecem 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 das quais você pode usar para executar E/S de System.IO
arquivo com armazenamento local de aplicativo nessas duas plataformas.
No entanto, se você procurar por essas System.IO
classes em uma Xamarin.Forms PCL, não as encontrará. O problema é que a Microsoft renovou completamente a E/S de arquivo para a API do Tempo de Execução do Windows. Programas destinados ao Windows 8.1, Windows Phone 8.1 e à Plataforma Universal do Windows não são usados System.IO
para E/S de arquivos.
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 oferece suporte System.IO
a tipos para todas as Xamarin.Forms plataformas. Não é mais necessário usar um para a maioria das tarefas de DependencyService
E/S de arquivo. Consulte Tratamento de arquivos para Xamarin.Forms obter uma abordagem mais moderna para E/S de arquivos.
Uma primeira chance de E/S de arquivos entre plataformas
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 de 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 executados no Tempo de Execução do Windows usam classes no Windows.Storage
e Windows.Storage.Streams
namespaces para E/S de arquivo, incluindo o armazenamento local do 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, um PCL normal Xamarin.Forms
- Xamarin.FormsBook.Platform.iOS, uma biblioteca de classes do iOS
- Xamarin.FormsBook.Platform.Android, uma biblioteca de classes 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 DependencyService
uso do 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 Xamarin.Formsbibliotecas Book.Platform . Cada um dos projetos tem uma chamada para Toolkit.Init
. O aplicativo faz uso das 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
e ReadFileASync
métodos na classe do Tempo de Execução do Windows FileHelper
— podem ser tornados um pouco mais eficientes usando o ConfigureAwait
método para evitar alternar 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 aguardados
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 a seguir.
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 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 e sair se CancellationToken
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 de usuário mais extensa e é principalmente baseado em classes e MandelbrotModel
MandelbrotViewModel
e:
Voltar para a Web
A WebRequest
classe usada em alguns exemplos usa um protocolo assíncrono antiquado chamado Modelo de Programação Assíncrona ou APM. Você pode converter tal classe para o protocolo TAP moderno usando um dos FromAsync
métodos na TaskFactory
classe. O exemplo ApmToTap demonstra isso.