我有一个页面,我在OnAppearing
方法中从API检索数据:
protected override async void OnAppearing()
{
var content = await _client.GetStringAsync(Url);
var footmarks = JsonConvert.DeserializeObject<List<Footmark>>(content);
_footmarks = new ObservableCollection<Footmark>(footmarks);
listView.ItemsSource = _footmarks;
base.OnAppearing();
}
这工作正常,但在同一页面上我有2个事件处理程序,我还需要进行相同的API调用。所以最好把它移到一个函数中。但是我怎么能这样做,因为事件处理程序不能被异步?
所以理想情况下我会像这样OnAppearing
:
protected override async void OnAppearing()
{
listView.ItemsSource = GetFootmarks();
base.OnAppearing();
}
然后是一个调用相同方法的事件处理程序:
void Handle_Refreshing(object sender, System.EventArgs e)
{
listView.ItemsSource = GetFootmarks();
listView.EndRefresh();
}
我怎样才能做到这一点?
我会这样走:
将api调用解压缩为一个方法:
async Task<List<Footmark>> GetFootMarksAsync()
{
var content = await _client.GetStringAsync(Url);
return JsonConvert.DeserializeObject<List<Footmark>>(content);
}
可以在OnAppearing中调用此方法
protected override async void OnAppearing()
{
_footmarks = new ObservableCollection<Footmark>(await GetFootMarksAsync());
listView.ItemsSource = _footmarks;
base.OnAppearing();
}
在EventHandler中,它可以以相同的方式使用。只有更改是使用async关键字标记处理程序。
async void Handle_Refreshing(object sender, System.EventArgs e)
{
_footmarks = new ObservableCollection<Footmark>(await GetFootMarksAsync());
listView.ItemsSource = _footmarks;
listView.EndRefresh();
}
所以最好把它移到一个函数中。
将重复的功能提取到自己的功能中是明智的选择。
async Task<ObservableCollection<Footmark>> GetFootmarks() {
var json = await _client.GetStringAsync(Url);
return JsonConvert.DeserializeObject<ObservableCollection<Footmark>>(json);
}
这将允许您在整个依赖类中调用它。
您甚至应该考虑将其提取到自己的服务中,该服务可以在应用程序的其他部分中重用。
public interface IFoomarkService {
Task<ObservableCollection<Footmark>> GetFootmarks();
}
但是我怎么能这样做,因为事件处理程序不能被异步?
事件处理程序可以异步。
参考Async/Await - Best Practices in Asynchronous Programming
避免使用async void
,唯一的例外是实际的事件处理程序。
遗憾的是,OnAppearing()
不是一个事件处理程序,而是一个实际的虚方法。
但是,在框架调用Appearing
之后会引发OnAppearing
事件,这意味着您可以在那里订阅事件并在引发时在该事件的实际事件处理程序中执行异步操作。
protected override void OnAppearing() {
this.Appearing += Page_Appearing; //Subscribe to event
base.OnAppearing();
}
protected async void Page_Appearing(object sender, EventArgs args) {
listView.ItemsSource = await GetFootmarks(); //get data asynchronously
//this.Appearing -= Page_Appearing; //Unsubscribe (OPTIONAL but advised)
}
protected async void Handle_Refreshing(object sender, System.EventArgs e) {
listView.ItemsSource = await GetFootmarks(); //get data asynchronously
listView.EndRefresh();
}