Xamarin.Formsで開発する時に非同期処理を結構使うのですが、いつも悩むのが非同期処理のメソッドをページ遷移と同時に実行するにはどうすればいいのかということです。というわけで自分なりに色々考えてみました。
どんな方法がある?
パターンとしては以下の3通りがあると思います。
1. ViewまたはViewModelのコンストラクタ内で実行する
2. ViewのOnAppearing
メソッドで実行する
3. ViewのAppearing
イベントで実行する
1と2の方法は、コンストラクタ自体は非同期にできないので、呼び出す非同期メソッドをasync void
とすれば画面上の動きとしてはうまくいっているように見えます。しかし、非同期処理について調べると「async void
はイベントハンドラ以外では使わない」というのが鉄則のようです。また、Visual Studioからも「非同期メソッドでvoidを返すべきではない」と注意されます。
イベントハンドラを使えばいい!
そこで3の方法です。イベントなのでasync void
でも問題ないはずです。具体例としてコードを書くと以下のようなります。ページ遷移直後は待機中
と表示し、3秒後に待機完了
という文字列に変更するものです。
View
<?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:XF_VmConstructor" Appearing="MainPage_Appearing" x:Class="XF_VmConstructor.MainPage"> <ContentPage.BindingContext> <local:MainPageViewModel x:Name="mainPageViewModel"/> </ContentPage.BindingContext> <StackLayout> <Label Text="{Binding Label}" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" /> </StackLayout> </ContentPage>
コードビハインド
using System; using System.ComponentModel; using Xamarin.Forms; namespace XF_VmConstructor { [DesignTimeVisible(true)] public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } async void MainPage_Appearing(object sender, EventArgs e) { await mainPageViewModel.AsyncMethod(); } } }
ViewModel
using System.ComponentModel; using System.Threading.Tasks; namespace XF_VmConstructor { public class MainPageViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public async Task AsyncMethod() { Label = "待機中"; await Task.Delay(3000); Label = "待機完了"; } private string label; public string Label { get { return label; } set { if(label != value) { label = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Label))); } } } } }
ViewModelで非同期なメソッドを定義して、ViewのAppearingイベントで呼び出しています。 この方法ならVisual Studioにも怒られずに済みます。
気になっているのが、Xamarin.Formsのサンプルコードでasync void
を使っているメソッドをたまに見るんですよね(async void OnAppearing
とか)。それでも問題ないんですかね??やはり非同期処理についてしっかり理解しなければダメだな・・・。
といったところで今回は失礼します。