Podsumowanie rozdziału 20. Asynchroniczne operacje we/wy i operacje we/wy plików
Uwaga
Ta książka została opublikowana wiosną 2016 roku i od tego czasu nie została zaktualizowana. Jest wiele w książce, która pozostaje cenna, ale niektóre materiały są nieaktualne, a niektóre tematy nie są już całkowicie poprawne ani kompletne.
Graficzny interfejs użytkownika musi reagować sekwencyjnie na zdarzenia wejściowe użytkownika. Oznacza to, że wszystkie operacje przetwarzania zdarzeń wejściowych użytkownika muszą występować w jednym wątku, często nazywanym wątkiem głównym lub wątkiem interfejsu użytkownika.
Użytkownicy oczekują, że graficzne interfejsy użytkownika będą reagować. Oznacza to, że program musi szybko przetwarzać zdarzenia wejściowe użytkownika. Jeśli to nie jest możliwe, przetwarzanie musi zostać zdegradowane do pomocniczych wątków wykonywania.
W tej książce użyto WebRequest
kilku przykładowych programów. W tej klasie BeginGetResponse
metoda uruchamia wątek procesu roboczego, który wywołuje funkcję wywołania zwrotnego po zakończeniu. Jednak ta funkcja wywołania zwrotnego jest uruchamiana w wątku procesu roboczego, więc program musi wywołać Device.BeginInvokeOnMainThread
metodę w celu uzyskania dostępu do interfejsu użytkownika.
Uwaga
Xamarin.Forms programy powinny być używane HttpClient
, a nie WebRequest
do uzyskiwania dostępu do plików przez Internet. HttpClient
obsługuje operacje asynchroniczne.
Bardziej nowoczesne podejście do przetwarzania asynchronicznego jest dostępne na platformie .NET i w języku C#. Obejmuje Task
to klasy i Task<TResult>
oraz inne typy w System.Threading
przestrzeniach nazw iSystem.Threading.Tasks
, a także słowa kluczowe języka C# 5.0async
.await
To właśnie ten rozdział koncentruje się na.
Od wywołań zwrotnych do oczekiwania
Sama Page
klasa zawiera trzy metody asynchroniczne do wyświetlania pól alertów:
DisplayAlert
Task
zwraca obiektDisplayAlert
Task<bool>
zwraca obiektDisplayActionSheet
Task<string>
zwraca obiekt
Obiekty Task
wskazują, że te metody implementują asynchroniczny wzorzec oparty na zadaniach, znany jako TAP. Te Task
obiekty są szybko zwracane z metody . Wartości Task<T>
zwracane stanowią "obietnicę", że wartość typu TResult
będzie dostępna po zakończeniu zadania. Wartość Task
zwracana wskazuje akcję asynchroniczną, która zostanie ukończona, ale bez zwracanej wartości.
We wszystkich tych przypadkach element Task
zostanie ukończony, gdy użytkownik odrzuci pole alertu.
Alert z wywołaniami zwrotnymi
W przykładzie AlertCallbacks pokazano, jak obsługiwać Task<bool>
obiekty zwracane i Device.BeginInvokeOnMainThread
wywołania przy użyciu metod wywołania zwrotnego.
Alert z lambdami
W przykładzie AlertLambdas pokazano, jak używać anonimowych funkcji lambda do obsługi wywołań i Device.BeginInvokeOnMainThread
ich obsługiTask
.
Alert z oczekiwaniem
Bardziej proste podejście obejmuje async
słowa kluczowe i await
wprowadzone w języku C# 5. Przykład AlertAwait demonstruje ich użycie.
Alert z niczym
Jeśli metoda asynchroniczna zwraca Task
wartość zamiast Task<TResult>
, program nie musi używać żadnej z tych technik, jeśli nie musi wiedzieć, kiedy zadanie asynchroniczne zostanie zakończone. Przykład NothingAlert pokazuje to.
Asynchroniczne zapisywanie ustawień programu
W przykładzie SaveProgramChanges pokazano użycie SavePropertiesAsync
metody Application
zapisywania ustawień programu w miarę ich zmiany bez zastępowania OnSleep
metody .
Czasomierz niezależny od platformy
Istnieje możliwość utworzenia Task.Delay
czasomierza niezależnego od platformy. Przykład TaskDelayClock pokazuje to.
Dane wejściowe/wyjściowe pliku
Tradycyjnie przestrzeń nazw platformy .NET System.IO
była źródłem obsługi we/wy plików. Chociaż niektóre metody w tej przestrzeni nazw obsługują operacje asynchroniczne, większość z nich nie obsługuje. Przestrzeń nazw obsługuje również kilka prostych wywołań metod, które wykonują zaawansowane funkcje we/wy plików.
Dobra wiadomość i złe wieści
Wszystkie platformy obsługiwane przez Xamarin.Forms obsługę magazynu lokalnego aplikacji — magazyn prywatny dla aplikacji.
Biblioteki platform Xamarin.iOS i Xamarin.Android zawierają wersję platformy .NET, którą platforma Xamarin została wyraźnie dopasowana do tych dwóch platform. Należą do nich klasy System.IO
, których można użyć do wykonywania operacji we/wy plików z magazynem lokalnym aplikacji na tych dwóch platformach.
Jeśli jednak wyszukasz te System.IO
klasy w Xamarin.Forms PCL, nie znajdziesz ich. Problem polega na tym, że firma Microsoft całkowicie przebudował we/wy pliku dla interfejsu API środowisko wykonawcze systemu Windows. Programy przeznaczone dla systemu Windows 8.1, Windows Phone 8.1 i platforma uniwersalna systemu Windows nie są używane System.IO
do we/wy pliku.
Oznacza to, że należy użyć elementu DependencyService
(po raz pierwszy omówionego w rozdziale 9). Wywołania interfejsu API specyficzne dla platformy do implementowania operacji we/wy plików.
Uwaga
Przenośne biblioteki klas zostały zastąpione bibliotekami .NET Standard 2.0, a platforma .NET Standard 2.0 obsługuje System.IO
typy dla wszystkich Xamarin.Forms platform. Nie jest już konieczne używanie elementu DependencyService
dla większości zadań we/wy plików. Aby uzyskać bardziej nowoczesne podejście do operacji we/wy plików, zobacz Obsługa plików w programie Xamarin.Forms .
Pierwszy strzał w wieloplatformowym pliku we/wy
Przykład TextFileTryout definiuje IFileHelper
interfejs dla we/wy plików i implementacje tego interfejsu na wszystkich platformach. Jednak implementacje środowisko wykonawcze systemu Windows nie działają z metodami w tym interfejsie, ponieważ metody we/wy pliku środowisko wykonawcze systemu Windows są asynchroniczne.
Alokowanie operacji we/wy pliku środowisko wykonawcze systemu Windows
Programy działające w ramach środowisko wykonawcze systemu Windows używają klas w przestrzeniach nazw i Windows.Storage.Streams
dla we/wy plików, w Windows.Storage
tym magazynu lokalnego aplikacji. Ponieważ firma Microsoft ustaliła, że każda operacja wymagająca więcej niż 50 milisekund powinna być asynchroniczna, aby uniknąć blokowania wątku interfejsu użytkownika, te metody we/wy plików są głównie asynchroniczne.
Kod demonstrujący to nowe podejście będzie znajdować się w bibliotece, dzięki czemu może być używany przez inne aplikacje.
Biblioteki specyficzne dla platformy
Korzystne jest przechowywanie kodu wielokrotnego użytku w bibliotekach. Jest to oczywiście trudniejsze, gdy różne fragmenty kodu wielokrotnego użytku są przeznaczone dla zupełnie różnych systemów operacyjnych.
Rozwiązanie Xamarin.FormsBook.Platform demonstruje jedno podejście. To rozwiązanie zawiera siedem różnych projektów:
- Xamarin.FormsBook.Platform, normalny Xamarin.Forms PCL
- Xamarin.FormsBook.Platform.iOS, biblioteka klas systemu iOS
- Xamarin.FormsBook.Platform.Android, biblioteka klas systemu Android
- Xamarin.FormsBook.Platform.UWP, biblioteka klas uniwersalnego systemu Windows
- Xamarin.FormsBook.Platform.WinRT, udostępniony projekt kodu, który jest wspólny dla wszystkich platform systemu Windows
Wszystkie poszczególne projekty platform (z wyjątkiem Xamarin.FormsBook.Platform.WinRT) mają odwołania do Xamarin.FormsBook.Platform. Trzy projekty systemu Windows zawierają odwołanie do Xamarin.FormsBook.Platform.WinRT.
Wszystkie projekty zawierają metodę statyczną Toolkit.Init
, aby upewnić się, że biblioteka jest ładowana, jeśli nie jest bezpośrednio przywoływany przez projekt w rozwiązaniu Xamarin.Forms aplikacji.
Projekt Xamarin.FormsBook.Platform zawiera nowy IFileHelper
interfejs. Wszystkie metody mają teraz nazwy z Async
sufiksami i zwracanymi Task
obiektami.
Projekt Xamarin.FormsBook.Platform.WinRT zawiera klasę FileHelper
środowisko wykonawcze systemu Windows.
Projekt Xamarin.FormsBook.Platform.iOS zawiera klasę FileHelper
dla systemu iOS. Te metody muszą być teraz asynchroniczne. Niektóre metody używają asynchronicznych wersji metod zdefiniowanych w systemach StreamWriter
i : StreamReader
WriteAsync
i ReadToEndAsync
. Inni konwertują Task
wynik na obiekt przy użyciu FromResult
metody .
Projekt Xamarin.FormsBook.Platform.Android zawiera podobną FileHelper
klasę dla systemu Android.
Projekt Xamarin.FormsBook.Platform zawiera również klasę FileHelper
, która ułatwia korzystanie z DependencyService
obiektu.
Aby korzystać z tych bibliotek, rozwiązanie aplikacji musi zawierać wszystkie projekty w rozwiązaniu Xamarin.FormsBook.Platform , a każdy z projektów aplikacji musi mieć odwołanie do odpowiedniej biblioteki w Xamarin.Formsbook.platform.
Rozwiązanie TextFileAsync pokazuje, jak używać Xamarin.Formsbibliotek Book.Platform . Każdy z projektów ma wywołanie metody Toolkit.Init
. Aplikacja korzysta z asynchronicznych funkcji we/wy pliku.
Utrzymywanie go w tle
Metody w bibliotekach, które tworzą wywołania wielu metod asynchronicznych — takich jak WriteFileAsync
metody i ReadFileASync
w klasie środowisko wykonawcze systemu Windows FileHelper
— mogą być nieco bardziej wydajne przy użyciu ConfigureAwait
metody , aby uniknąć powrotu do wątku interfejsu użytkownika.
Nie blokuj wątku interfejsu użytkownika!
Czasami kuszące jest unikanie użycia właściwości ContinueWith
lub await
przy użyciu Result
właściwości w metodach. Należy tego uniknąć, ponieważ może zablokować wątek interfejsu użytkownika, a nawet zawiesić aplikację.
Własne metody oczekujące
Możesz uruchomić kod asynchronicznie, przekazując go do jednej z Task.Run
metod. Możesz wywołać Task.Run
metodę asynchroniową, która obsługuje niektóre obciążenia.
Różne Task.Run
wzorce zostały omówione poniżej.
Podstawowy zestaw Mandelbrot
Aby narysować mandelbrot ustawiony w czasie rzeczywistym, Xamarin.Forms. Biblioteka zestawu narzędzi ma strukturę podobną Complex
do tej w System.Numerics
przestrzeni nazw.
Przykład MandelbrotSet zawiera metodę CalculateMandeblotAsync
w pliku za kodem, która oblicza podstawowy zestaw mandelbrot i używa BmpMaker
go do umieszczania go na mapie bitowej.
Znakowanie postępu
Aby zgłosić postęp z metody asynchronicznej, możesz utworzyć wystąpienie klasy i zdefiniować metodę Progress<T>
asynchroniczną, aby mieć argument typu IProgress<T>
. Jest to pokazane w przykładzie MandelbrotProgress .
Anulowanie zadania
Możesz również napisać metodę asynchroniczną, aby można było anulować. Zaczynasz od klasy o nazwie CancellationTokenSource
. Właściwość Token
jest wartością typu CancellationToken
. Jest on przekazywany do funkcji asynchronicznej. Program wywołuje metodę Cancel
CancellationTokenSource
(zazwyczaj w odpowiedzi na akcję przez użytkownika), aby anulować funkcję asynchroniczną.
Metoda asynchroniczna może okresowo sprawdzać IsCancellationRequested
właściwość i wyjść, jeśli właściwość ma true
wartość CancellationToken
, lub po prostu wywołaj ThrowIfCancellationRequested
metodę , w tym przypadku metoda kończy się ciągiem OperationCancelledException
.
Przykład MandelbrotCancellation demonstruje użycie funkcji z możliwością anulowania.
An MVVM Mandelbrot
Przykład MandelbrotXF ma bardziej rozbudowany interfejs użytkownika i opiera się głównie na MandelbrotModel
klasach i MandelbrotViewModel
:
Powrót do sieci Web
Klasa WebRequest
używana w niektórych przykładach używa staroświetnego protokołu asynchronicznego nazywanego asynchronicznym modelem programowania lub APM. Taką klasę można przekonwertować na nowoczesny protokół TAP przy użyciu jednej z FromAsync
metod w TaskFactory
klasie . Przykład ApmToTap pokazuje to.