使用异步等待 C# Xamarin

Posted

技术标签:

【中文标题】使用异步等待 C# Xamarin【英文标题】:Using async await C# Xamarin 【发布时间】:2014-08-15 01:10:46 【问题描述】:

我最近开始使用 Xamarin,而且我对 c# 还很陌生。我想创建一个异步 HTTP 请求,所以我开始使用 async 并使用 HttpWebRequest 等待。但我没有得到异步调用,UI 正在阻塞。这是我正在测试的代码。我有两个实现,RequestCitas() 应该是异步的,而 SRequestCitas() 是同步的,有什么问题?

namespace mc

[Activity (Label = "mc", MainLauncher = true, Theme="@android:style/Theme.Holo.Light")]
public class MainActivity : Activity


    List<Cita> citas;
    CitaAdapter adapter;

    protected override void OnCreate (Bundle savedInstanceState)
    
        base.OnCreate (savedInstanceState);
        SetContentView (Resource.Layout.Main);


        citas = new List<Cita> ();
        adapter = new CitaAdapter (this, citas);
        ListView listView = FindViewById<ListView> (Resource.Id.main_citas);
        listView.Adapter = adapter;

        var c1 = new Cita (0, "ernesto", "De los Santos", "19/2/14", "19/2/14", "09:28", "10:45");
        var c2 = new Cita (1, "ernesto", "De los Santos", "19/2/14", "19/2/14", "09:28", "10:45");
        var c3 = new Cita (2, "ernesto", "De los Santos", "19/2/14", "19/2/14", "09:28", "10:45");
        var c4 = new Cita (3, "ernesto", "De los Santos", "19/2/14", "19/2/14", "09:28", "10:45");
        var c5 = new Cita (4, "ernesto", "De los Santos", "19/2/14", "19/2/14", "09:28", "10:45");

        citas.Add (c1);
        citas.Add (c2);
        citas.Add (c3);
        citas.Add (c4);
        citas.Add (c5);

        Console.WriteLine ("Notificando al adaptador");
        adapter.NotifyDataSetChanged ();

        string result;

        FindViewById<Button> (Resource.Id.button1).Click += async (sender, e) => 
            result =  await RequestCitas ();
        ;
        FindViewById<Button> (Resource.Id.button2).Click += delegate 
            result = SRequestCitas ();
        ;
    

    private async Task<string>  RequestCitas ()
    

        // var url = "http://192.168.1.126:8081";
        var url = "http://192.168.1.124";
        //var method = "/citas/get";
        var method = "";

        var encoding = new UTF8Encoding ();
        byte[] parametros = encoding.GetBytes ("usersID=97");

        var request = (HttpWebRequest)WebRequest.Create (url + method);
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = parametros.Length;

        var dataStream = request.GetRequestStream ();
        dataStream.Write (parametros, 0, parametros.Length);
        dataStream.Close ();

        string str = ""; 

        Task<WebResponse> task = request.GetResponseAsync ();

        WebResponse newResponse = await task;

        var responseStream = newResponse.GetResponseStream ();
        var streamReader = new StreamReader (responseStream, System.Text.Encoding.GetEncoding ("utf-8"));
        char[] read = new Char[256];
        int count = streamReader.Read (read, 0, 256);

        while (count > 0) 
            str += new string (read, 0, count);
            count = streamReader.Read (read, 0, 256);
        
        responseStream.Close ();

        return str;
    


    private string SRequestCitas ()
    

        var url = "http://192.168.1.126:8081";
        var method = "/citas/get";

        var encoding = new UTF8Encoding ();
        byte[] parametros = encoding.GetBytes ("usersID=97");

        var request = (HttpWebRequest)WebRequest.Create (url + method);
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = parametros.Length;

        var dataStream = request.GetRequestStream ();
        dataStream.Write (parametros, 0, parametros.Length);
        dataStream.Close ();

        string str = ""; 

        HttpWebResponse newResponse = (HttpWebResponse)request.GetResponse ();

        var responseStream = newResponse.GetResponseStream ();
        var streamReader = new StreamReader (responseStream, System.Text.Encoding.GetEncoding ("utf-8"));
        char[] read = new Char[256];
        int count = streamReader.Read (read, 0, 256);

        while (count > 0) 
            str += new string (read, 0, count);
            count = streamReader.Read (read, 0, 256);
        
        responseStream.Close ();

        return str;
    



【问题讨论】:

你的代码能编译吗?您在非异步 void 方法中使用 await 。此外,看起来您的 while 循环阻塞了您的 UI,而不是等待的任务 【参考方案1】:

您正在使用async 方法获得响应,但您正在使用同步流操作读取流。尝试改用streamReader.ReadAsync

或者,如果您有野心,可以尝试完全替换整个 while 循环并使用:

var str = await streamReader.ReadToEndAsync();

顺便说一句,StreamReader 实现了IDisposable,当您完成实例时,您没有正确处理它。您可能正在泄漏本机资源。

【讨论】:

【参考方案2】:

当您创建一个使用await 关键字的方法时,我必须将它标记为async 以便编译器允许使用该关键字。此外,您应该遵循指南并以 Async 前缀结束您的方法

您的 async 方法正在从 StreamReader 同步读取,这导致您的 UI 阻塞。

这是一个使用 HttpClient 的异步实现:

private async Task<string> RequestCitasAsync()

    var url = "http://192.168.1.126:8081/citas/get";
    byte[] parametros = Encoding.UTF8.GetBytes("usersID=97");

    var httpClient = new HttpClient();
    var response = await httpClient.PostAsync(url, new ByteArrayContent(parametros));

    return await response.Content.ReadAsStringAsync();

【讨论】:

以上是关于使用异步等待 C# Xamarin的主要内容,如果未能解决你的问题,请参考以下文章

使用异步/等待 - C# [关闭]

C# 异步命名管道永远等待

Swift 中的 C# 异步等待

如何在c#中正确实现等待异步[重复]

C#异步编程概念和使用

C# 理解阻塞 UI 和异步/等待与 Task.Run 的问题?