HttpClient使用异步/等待操作获取列表

时间:2017-05-29 13:43:04

标签: c# asynchronous xamarin async-await httpclient

我试图从我之前写过的网络API中获取一个列表。然后我将在Xamarin.Forms ListView中使用该列表。我的代码在这里:

public static class DataSource
{

    public static async Task<Restoran[]> GetRestoransAsync()
    {
        // ... Use HttpClient.
        using (HttpClient client = new HttpClient())
        using (HttpResponseMessage response = await client.GetAsync(page))
        using (HttpContent content = response.Content)
        {
            // ... Read the string.
            string result = await content.ReadAsStringAsync();

            var restorans = JsonConvert.DeserializeObject<Restoran[]>(result);
            return restorans;
        }

    }

}

我的ContentPage:

public class MenuPage : ContentPage
{
    ListView listView;
    List<Restoran> restorans = new List<Restoran>();
    async Task LoadRestorans()
    {
        restorans = (await DataSource.GetRestoransAsync()).ToList();
    }

    public MenuPage(string masa)
    {
        var loadData = LoadRestorans();
        loadData.Wait();
        listView = new ListView(ListViewCachingStrategy.RecycleElement)
        {
        ItemsSource = restorans,
            ItemTemplate = new DataTemplate(() => {
                var nativeCell = new CustomCell();
                return nativeCell;
            })
        };
    }
}

但是当我调试这段代码时,&#34; LoadRestorans()&#34;方法在&#34; restorans&#34;的初始化之前调用。名单。我想我不了解异步方法的心态。我该怎么办?

2 个答案:

答案 0 :(得分:1)

您有两种选择。

使用异步工厂方法

创建页面
public class MenuPage : ContentPage {
    ListView listView;
    List<Restoran> restorans = new List<Restoran>();

    private async Task LoadRestoransAsync() {
        restorans = (await DataSource.GetRestoransAsync()).ToList();
        listView = new ListView(ListViewCachingStrategy.RecycleElement) {
            ItemsSource = restorans,
            ItemTemplate = new DataTemplate(() => {
                var nativeCell = new CustomCell();
                return nativeCell;
            })
        };
    }

    public MenuPage(string masa) {
        //...        
    }

    public static async Task<MenuPage> CreateMenuPageAsync(string masa) {
        var page = new MenuPage(masa);
        await page.LoadRestoransAsync();
        return pagel
    }
}

然后在其他异步事件处理程序中使用它

var page = await MenuPage.CreateMenuPageAsync("<masa here>");

OnAppearing事件中执行此操作。

订阅页面/视图的Appearing事件

protected override void OnAppearing() {
    this.Appearing += Page_Appearing;
}

并在实际的偶数处理程序上调用异步代码

private async void Page_Appearing(object sender, EventArgs e) {
    //...call async code here

    //unsubscribing from the event
    this.Appearing -= Page_Appearing;
}

完整的课程看起来像这样

public class MenuPage : ContentPage {
    ListView listView;
    List<Restoran> restorans = new List<Restoran>();

    private async Task LoadRestoransAsync() {
        restorans = (await DataSource.GetRestoransAsync()).ToList();
        listView = new ListView(ListViewCachingStrategy.RecycleElement) {
            ItemsSource = restorans,
            ItemTemplate = new DataTemplate(() => {
                var nativeCell = new CustomCell();
                return nativeCell;
            })
        };
    }

    public MenuPage(string masa) {
        //...        
    }

    protected override void OnAppearing() {
        this.Appearing += Page_Appearing;
    }

    private async void Page_Appearing(object sender, EventArgs e) {
        //...call async code here
        await LoadRestoransAsync();

        //unsubscribing from the event
        this.Appearing -= Page_Appearing;
    }

}

之前发生的事情是通过调用.Wait(),这是一个阻塞调用,该类混合了异步和阻塞调用(如.Result.Wait()),这可能导致死锁。因此,当您尝试测试时,为什么您无法通过该方法。

答案 1 :(得分:0)

restorans之前调用,因为在初始化属性之前调用了构造函数MenuPage

我建议

public class MenuPage : ContentPage
{
    ListView listView;
    List<Restoran> restorans;
    async Task<Restoran[]> LoadRestorans()
    {
        return await DataSource.GetRestoransAsync();
    }

    public MenuPage(string masa)
    {
        this.restorans = LoadRestorans().GetAwaiter().GetResult().ToList();
        listView = new ListView(ListViewCachingStrategy.RecycleElement)
        {
        ItemsSource = this.restorans,
            ItemTemplate = new DataTemplate(() => {
                var nativeCell = new CustomCell();
                return nativeCell;
            })
        };
    }
}

注意:我没有编译这段代码,但根据我的理解,这应该是正确的代码。