使用HttpWebRequest时应用程序挂起

时间:2016-03-22 21:21:44

标签: c# windows-phone-8.1 win-universal-app

我正在使用C#开发一个从互联网下载文件的应用程序(我不想使用后台下载程序!) 这是下载的类代码:

public class DL
{
    public event Progresses OnProgress;
    Stopwatch stopwatch = new Stopwatch();

    public async void Get(string url, StorageFile destinationFile)
    {
        stopwatch.Reset();
        stopwatch.Start();
        HttpWebRequest request = (HttpWebRequest)WebRequest.
            Create(url);
        HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
        long size = response.ContentLength;
        long downloaded = 0;


        using (Stream inputStream = response.GetResponseStream())
        using (Stream outputStream = await destinationFile.OpenStreamForWriteAsync())
        {
            byte[] buffer = new byte[1024];
            int bytesRead;
            do
            {
                bytesRead = inputStream.Read(buffer, 0, buffer.Length);
                downloaded += bytesRead;
                outputStream.Write(buffer, 0, bytesRead);
                int secondsRemaining = (int)(stopwatch.Elapsed.TotalSeconds
                    / downloaded * (size - downloaded));
                TimeSpan span = new TimeSpan(0, 0, 0, secondsRemaining);
                string remainTime = string.Format("{0}:{1}:{2}", span.Hours, span.Minutes, span.Seconds);
                OnProgress(remainTime);
            } while (bytesRead != 0);
        }
    }
}

public delegate void Progresses(string text);

这就是下载文件的方法:

private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
    DL webGard = new DL();
    webGard.OnProgress += WebGard_OnProgress;
    StorageFile destinationFile = await KnownFolders.MusicLibrary
       .CreateFileAsync("r58.zip", CreationCollisionOption.GenerateUniqueName);
    string url = "my url";
    webGard.Get(url, destinationFile);
}

private async void WebGard_OnProgress(string text)
{
    System.Diagnostics.Debug.WriteLine(text);
    var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        textBlock.Text = text;
    });
}

当我按下下载按钮时,应用程序当前进入挂起并且无法使用它直到下载结束,我想向用户显示剩余时间,此代码适用于visual studio中的输出窗口但是UI被挂起而且不能在textBlock中显示结果。

如何解决此问题? 感谢

1 个答案:

答案 0 :(得分:1)

这里的问题是你正在使用所有正确的异步命令来启动,这很棒。不幸的是,当您实际从流中读取数据时,您将同步执行此操作。这就是我的意思......

初始化流后,您将开始使用循环读取和写入数据。如果查看do / while循环,您将看到所有操作都是同步完成的。此循环中有两个工作项导致您的重要应用程序挂起。这一行:

bytesRead = inputStream.Read(buffer, 0, buffer.Length);

和这一行:

outputStream.Write(buffer, 0, bytesRead);

在循环的每次迭代期间,当您等待来自服务器的带有下一个数据块的响应时,您将阻止应用程序线程。这意味着您不仅要等待服务器回复,还要等待通过网络传输此数据的延迟。除此之外,当您将此数据写回文件时,您将被文件系统阻止。相反,您应该使用流的ReadAsyncWriteAsync方法。

这样,实际上只在实际上在内存中移动数据时,只会在很短的时间内阻塞主线程。然后你回到等待流来完成他们的操作,同时你的应用程序UI线程可以自由地做它想要的。

我希望这有帮助!