次の方法で共有


第 20 章の概要: 非同期およびファイル I/O

Note

この本は 2016 年春に発行されて以降、改訂されていません。 多くの情報はまだ価値がありますが、一部の資料は古くなっており、トピックの中にはまったく正しくないものまたは不完全なものもあります。

グラフィカル ユーザー インターフェイスは、ユーザー入力イベントに順番に応答する必要があります。 これは、ユーザー入力イベントのすべての処理が、1 つのスレッド ("メイン スレッド" または "UI スレッド" と呼ばれることが多い) 内で発生する必要があることを示しています。

ユーザーは、グラフィカル ユーザー インターフェイスがレスポンシブであることを期待しています。 これは、プログラムで迅速にユーザー入力イベントを処理する必要があることを意味しています。 これが不可能な場合、処理は実行のセカンダリ スレッドに回される必要があります。

この書籍に含まれているいくつかのサンプル プログラムでは、WebRequest クラスが使用されています。 このクラスでは、BeginGetResponse メソッドによってワーカー スレッドが開始されます。これが完了すると、コールバック関数が呼び出されます。 ただし、そのコールバック関数はワーカー スレッドで実行されるため、プログラムではユーザー インターフェイスにアクセスするために、Device.BeginInvokeOnMainThread メソッドを呼び出す必要があります。

Note

Xamarin.Forms プログラムでは、インターネット経由でファイルにアクセスするために、WebRequest ではなく HttpClient を使用する必要があります。 HttpClient では非同期操作がサポートされています。

.NET および C# では、非同期処理に対するより新しいアプローチを使用できます。 そこでは、Task および Task<TResult> クラス、System.Threading および System.Threading.Tasks 名前空間のその他の型、C# 5.0 の async および await キーワードが使用されます。 この章では、これに焦点を当てます。

コールバックから await まで

Page クラス自体に、アラート ボックスを表示するための 3 つの非同期メソッドが含まれています。

Task オブジェクトは、これらのメソッドでタスク ベースの非同期パターン (TAP と呼ばれます) が実装されていることを示します。 これらの Task オブジェクトは、メソッドからすぐに返されます。 戻り値 Task<T> は、タスクの完了時に TResult 型の値を使用できるようになる "約束" を構成します。 戻り値 Task は非同期アクションを示します。これは完了しても、値は返されません。

これらのケースすべてにおいて、Task は、ユーザーがアラート ボックスを閉じたときに完了します。

コールバックを使用したアラート

AlertCallbacks サンプルは、Task<bool> の戻り値オブジェクトと Device.BeginInvokeOnMainThread 呼び出しを、コールバック メソッドを使用して処理する方法を示しています。

ラムダを使用したアラート

AlertLambdas サンプルは、TaskDevice.BeginInvokeOnMainThread の呼び出しを処理するために、匿名のラムダ関数を使用する方法を示しています。

await を使用したアラート

よりわかりやすい方法は、C# 5 で導入された async および await キーワードを使用するものです。 AlertAwait サンプルは、それらの使用方法を示しています。

何も使用しないアラート

非同期メソッドが Task<TResult> ではなく Task を返した場合、プログラムで非同期タスクがいつ完了するかを知る必要がなければ、これらの手法を使用する必要はありません。 NothingAlert サンプルはこのケースを示しています。

プログラムの設定を非同期に保存する

SaveProgramChanges サンプルは、ApplicationSavePropertiesAsync メソッドを使用して、OnSleep メソッドをオーバーライドせずに、プログラムの設定が変更されたときにその設定を保存する方法を示しています。

プラットフォームに依存しないタイマー

Task.Delay を使用して、プラットフォームに依存しないタイマーを作成することができます。 TaskDelayClock サンプルはこの方法を示しています。

ファイルの入出力

従来は、.NET の System.IO 名前空間がファイル I/O のサポートのソースでした。 この名前空間の一部のメソッドでは非同期操作がサポートされていますが、ほとんどのメソッドではサポートされていません。 この名前空間では、高度なファイル I/O 関数を実行する、いくつかのシンプルなメソッド呼び出しもサポートされています。

良いニュースと悪いニュース

Xamarin.Forms でサポートされているすべてのプラットフォームでは、アプリケーションのローカル ストレージ、すなわち、アプリケーション専用のストレージがサポートされています。

Xamarin.iOS と Xamarin.Android のライブラリには、これらの 2 つのプラットフォーム向けに Xamarin によって特別に調整されたバージョンの .NET が含まれています。 これらには System.IO のクラスが含まれています。これらを使用すると、これら 2 つのプラットフォームでアプリケーションのローカル ストレージでのファイル I/O を実行できます。

しかし、Xamarin.Forms PCL でこれらの System.IO クラスを検索しても、見つかりません。 問題は、Microsoft によって、Windows ランタイム API のファイル I/O が完全に改良されたことです。 Windows 8.1、Windows Phone 8.1、およびユニバーサル Windows プラットフォームをターゲットとするプログラムでは、ファイル I/O に System.IO が使用されません。

つまり、DependencyService を使用して (最初に「第 9 章: プラットフォーム固有の API 呼び出し」で説明されています)、ファイル I/O を実装する必要があります。

Note

ポータブル クラス ライブラリは .NET Standard 2.0 ライブラリに置き換えられています。 .NET Standard 2.0 では、すべての Xamarin.Forms プラットフォーム向けに System.IO 型がサポートされています。 ほとんどのファイル I/O タスクでは、DependencyService を使用する必要がなくなりました。 ファイル I/O に対するより新しいアプローチについては、「Xamarin.Forms でのファイル処理」をご覧ください。

最初のクロスプラットフォーム ファイル I/O

TextFileTryout サンプルでは、ファイル I/O 用の IFileHelper インターフェイスと、すべてのプラットフォームでのこのインターフェイスの実装が定義されています。 しかし、Windows ランタイムの実装を、このインターフェイスのメソッドと連動させることはできません。Windows ランタイムのファイル I/O メソッドは非同期であるためです。

Windows ランタイムのファイル I/O に対応する

Windows ランタイムの下で実行されているプログラムでは、ファイル I/O 用に Windows.Storage および Windows.Storage.Streams 名前空間のクラスが使用されます。これにはアプリケーションのローカル ストレージが含まれます。 UI スレッドのブロックを防止するために、Microsoft によって、50 ミリ秒を超える処理を必要とする操作はすべて非同期にすることが決められています。そのため、これらのファイル I/O メソッドはほとんどが非同期です。

この新しいアプローチを示すコードは、他のアプリケーションで使用できるようにライブラリに追加されます。

プラットフォーム固有のライブラリ

再利用可能なコードをライブラリに保存しておくと便利です。 これは当然、再利用可能なコードのさまざまな部分がまったく異なるオペレーティング システム用である場合、より困難になります。

Xamarin.FormsBook.Platform ソリューションは、1 つの方法を示しています。 このソリューションには、7 つの異なるプロジェクトが含まれています。

すべての個別のプラットフォーム用のプロジェクト (Xamarin.FormsBook.Platform.WinRT を除く) には、Xamarin.FormsBook.Platform への参照が含まれています。 3 つの Windows プロジェクトには、Xamarin.FormsBook.Platform.WinRT への参照が含まれています。

ライブラリが、Xamarin.Forms アプリケーション ソリューション内のプロジェクトによって直接参照されていない場合に読み込まれるように、すべてのプロジェクトには静的な Toolkit.Init メソッドが含まれています。

Xamarin.FormsBook.Platform プロジェクトには、新しい IFileHelper インターフェイスが含まれています。 すべてのメソッドの名前に Async サフィックスが付けられ、Task オブジェクトが返されるようになりました。

Xamarin.FormsBook.Platform.WinRT プロジェクトには、Windows ランタイム用の FileHelper クラスが含まれています。

Xamarin.FormsBook.Platform.iOS プロジェクトには、iOS 用の FileHelper クラスが含まれています。 これらのメソッドは非同期になっています。 一部のメソッドでは、StreamWriterStreamReader で定義されているメソッドの非同期バージョン: WriteAsyncReadToEndAsync が使用されています。 その他では、FromResult メソッドを使用して、結果が Task オブジェクトに変換されます。

Xamarin.FormsBook.Platform.Android プロジェクトには、Android 用の類似した FileHelper クラスが含まれています。

Xamarin.FormsBook.Platform プロジェクトには、DependencyService オブジェクトの使用を容易にする FileHelper クラスも含まれています。

これらのライブラリを使用するには、アプリケーション ソリューションに Xamarin.FormsBook.Platform ソリューション内のすべてのプロジェクトを含め、また各アプリケーション プロジェクトに Xamarin.FormsBook.Platform 内の対応するライブラリへの参照を含める必要があります。

TextFileAsync ソリューションは、Xamarin.FormsBook.Platform ライブラリの使用方法を示しています。 各プロジェクトには Toolkit.Init の呼び出しが含まれています。 アプリケーションでは、非同期ファイル I/O 関数が使用されます。

これをバックグラウンドに保持する

複数の非同期メソッドの呼び出しを行うライブラリ内のメソッド (Windows ランタイム FileHelper クラスの WriteFileAsyncReadFileASync メソッドなど) は、ConfigureAwait メソッドを使用してユーザー インターフェイス スレッドへの切り替えを回避することで、多少効率を上げることができます。

UI スレッドをブロックしない

場合によっては、メソッドの Result プロパティを使用して、ContinueWithawait の使用を回避したくなることがあります。 これは、UI スレッドをブロックしたり、アプリケーションをハングさせたりする可能性があるため、行わないでください。

独自の待機可能メソッド

一部のコードを非同期に実行するには、それを Task.Run メソッドのいずれかに渡します。 オーバーヘッドの一部を処理する非同期メソッド内で、Task.Run を呼び出すことができます。

以下では、Task.Run のさまざまなパターンについて説明します。

基本的なマンデルブロ集合

マンデルブロ集合をリアルタイムで描画するために、Xamarin.Forms.Toolkit ライブラリには、System.Numerics 名前空間に含まれているものと同様の Complex 構造が含まれています。

MandelbrotSet サンプルでは、分離コード ファイルに CalculateMandeblotAsync メソッドが含まれています。これによって基本的な黒と白のマンデルブロ集合が計算され、BmpMaker を使用してビットマップに配置されます。

進行状況をマークする

非同期メソッドから進行状況を報告するには、Progress<T> クラスのインスタンスを作成し、IProgress<T> 型の引数を持つように非同期メソッドを定義することができます。 これは MandelbrotProgress サンプルで示されています。

ジョブの取り消し

取り消し可能な非同期メソッドを作成することもできます。 まず CancellationTokenSource という名前のクラスから開始します。 Token プロパティは CancellationToken 型の値です。 これは、非同期関数に渡されます。 プログラムでは、非同期関数を取り消すために、(通常はユーザーのアクションに応答して) CancellationTokenSourceCancel メソッドが呼び出されます。

非同期メソッドでは、CancellationTokenIsCancellationRequested プロパティを定期的にチェックし、プロパティが true の場合に終了させることができます。または、単純に ThrowIfCancellationRequested メソッドを呼び出すことができます。この場合、メソッドは OperationCancelledException で終了します。

MandelbrotCancellation サンプルは、取り消し可能な関数の使用方法を示しています。

MVVM のマンデルブロ

MandelbrotXF サンプルには、より豊富なユーザー インターフェイスが用意されています。これは、ほとんどの場合、MandelbrotModel クラスと MandelbrotViewModel クラスに基づいています。

Mandelbrot X F のトリプル スクリーンショット

Web に戻る

一部のサンプルで使用されている WebRequest クラスでは、非同期プログラミング モデルまたは APM と呼ばれる、旧式の非同期プロトコルが使用されています。 TaskFactory クラスの FromAsync メソッドのいずれかを使用して、このようなクラスを最新の TAP プロトコルに変換することができます。 ApmToTap サンプルでは、この方法が示されています。