【问题标题】:Unable to download Image from URL Xamarin Form无法从 URL Xamarin 表单下载图像
【发布时间】:2020-05-12 14:10:08
【问题描述】:

我正在开发一个 Xamarin 应用程序,它从数据库中检索信息,拍摄/选择照片并将它们上传到远程服务器,从远程服务器显示这些图像,用户可以通过点击并按下按钮来删除它们。最后一步是将存储在服务器中的图像下载到本地设备库。

这是我当前的按钮点击事件:

private void button_download_image_Clicked(object sender, EventArgs e)
{
        Uri image_url_format = new Uri(image_url);
        WebClient webClient = new WebClient();
        try
        {              
            webClient.DownloadDataAsync(image_url_format);
            webClient.DownloadDataCompleted += webClient_DownloadDataCompleted;
        }
        catch (Exception ex)
        {
            DisplayAlert("Error", ex.ToString(), "OK");
        }
}

webClient_DownloadDataCompleted 方法下方:

private void webClient_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
    try
    {
        Uri image_url_format = new Uri(image_url);
        byte[] bytes_image = e.Result;
        Stream image_stream = new MemoryStream(bytes_image);
        string dest_folder= Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
        string file_name= Path.GetFileName(image_url_format.LocalPath);
        string dest_path= Path.Combine(dest_folder, file_name);
        using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
        {
              image_stream.CopyTo(fileStream);
        }
              DisplayAlert("Alert", "Download completed!", "OK");
    }
    catch (Exception ex)
    {
        DisplayAlert("Error", ex.ToString(), "OK");
    }
}

但它不起作用,没有发现错误,我收到警告,警告我下载已完成。我还授予了 internetwrite_external_storageread_external_storage 的权限。

另一件事是图像在一段时间后出现在下载相册下的图库中,这是正确的。

对这种行为有任何想法吗?

编辑

在我的新按钮下载事件下方:

private void button_download_image_Clicked(object sender, EventArgs e)
{

    Uri image_url_format = new Uri(image_url);
    WebClient webClient = new WebClient();
    try
    {
        byte[] bytes_image = webClient.DownloadData(image_url_format);
        Stream image_stream = new MemoryStream(bytes_image);
        string dest_folder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
        string file_name = Path.GetFileName(image_url_format.LocalPath);
        string dest_path = Path.Combine(dest_folder, file_name);
        using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
        {
            image_stream.CopyTo(fileStream);
        }
    }
    catch (Exception ex)
    {
        DisplayAlert("Error", ex.ToString(), "OK");
    }
    DisplayAlert("Alert", "File scaricato con successo", "OK");
}

【问题讨论】:

  • 由于您的图片出现在图库中,就好像它实际上已经下载了一样。请更彻底地描述预期的行为是什么,b/c 从你写的内容中并不清楚。
  • @PaulKertscher 预期的行为是:按下下载按钮 -> 图像将保存在设备的 Downloads 文件夹中。一切顺利,但图像没有出现在文件夹中,也没有出现在图库中。
  • 您是否使用文件资源管理器检查它确实不存在。可能是由于某种原因,图库无法正确刷新。
  • @PaulKertscher 是的,我检查了文件资源管理器但没有成功。奇怪的是,当我连接到我家的wifi时,我可以在图库中看到图像,这只是巧合吗?

标签: c# xamarin xamarin.forms download xamarin.android


【解决方案1】:

原因

您的功能“触发并忘记”下载,然后直接向您显示“下载完成”弹出窗口。原因是您正在以同步方式调用 异步 函数 (DownloadDataAsync)...这就是为什么它仍然会在一段时间后出现在图库中,而您仍然会弹出窗口。

解决方案

您应该首先阅读:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

然后作为起点,尝试将事件处理程序声明为异步并在适当的位置使用 await 关键字:

private async void button_download_image_Clicked(object sender, EventArgs e)
{
    Uri image_url_format = new Uri(image_url);
    WebClient webClient = new WebClient();
    try
    {            
        await webClient.DownloadDataAsync(image_url_format); // This will await the download
        ...
    }
    catch (Exception ex)
    {
        ...
    }
}

当然,最好也使用 async/await 模式一直重构其他方法,但我想这会给你一个很好的起点。

编辑:

关于你编辑的新方法,尝试使用DownloadDataTaskAsyncCopyToAsync方法以及async/await模式:

 private async void  button_download_image_Clicked(object sender, EventArgs e)
    {

        Uri image_url_format = new Uri("url");
        WebClient webClient = new WebClient();
        try
        {
            byte[] bytes_image = await webClient.DownloadDataTaskAsync(image_url_format);
            Stream image_stream = new MemoryStream(bytes_image);
            string dest_folder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
            string file_name = Path.GetFileName(image_url_format.LocalPath);
            string dest_path = Path.Combine(dest_folder, file_name);
            using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
            {
                await image_stream.CopyToAsync(fileStream);
            }
        }
        catch (Exception ex)
        {
           await DisplayAlertAsync("Error", ex.ToString(), "OK");
        }
        await DisplayAlertAsync("Alert", "File scaricato con successo", "OK");
    }

另外,您应该创建一个 DisplayAlertAsync 方法并使用 await 以相同的方式调用它。

编码愉快!

【讨论】:

  • 已尝试,但将等待添加到 DownloadDataAsync 时返回错误。我添加了修改后的下载方式。
  • @LeonardoBassi 那么这是一个起点。仔细阅读异常消息并尝试相应地修复您的代码。
  • @PaulKertscher 现在我可以在文件资源管理器中看到图像,但在图库中看不到。
  • @LeonardoBassi 这对你有帮助吗?如果是这样,您可以将其标记为答案,以便帮助其他有相同情况的人。干杯。
【解决方案2】:

图片已正确下载,我可以在文件资源管理器中看到它。

我通过重新刷新画廊解决了我的问题,在保存我的图像后使用这条线,所以方法是:

private void button_download_image_Clicked(object sender, EventArgs e)
{
    Uri image_url_format = new Uri(image_url);
    WebClient webClient = new WebClient();
    try
    {
        byte[] bytes_image = webClient.DownloadData(image_url_format);
        Stream image_stream = new MemoryStream(bytes_image);
        string dest_folder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).ToString();
        string file_name = Path.GetFileName(image_url_format.LocalPath);
        string dest_path = Path.Combine(dest_folder, file_name);
        using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
        {
            image_stream.CopyTo(fileStream);
        }
        // this 3 lines fix my problem
        var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
        mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(dest_path)));
        Android.App.Application.Context.SendBroadcast(mediaScanIntent);
    }
    catch (Exception ex)
    {
        DisplayAlert("Error", ex.ToString(), "OK");
    }
    DisplayAlert("Alert", "File scaricato con successo", "OK");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-30
    • 2017-08-03
    • 2018-02-04
    • 2020-09-26
    • 1970-01-01
    • 2015-06-15
    相关资源
    最近更新 更多