简体   繁体   English

无法从 URL Xamarin Form 下载图像

[英]Unable to download Image from URL Xamarin Form

I am developing a Xamarin app which retrives info from DB, take/choose photo and upload them to remote server, display this images from the remote server and the user can delete them by tap on and press a button.我正在开发一个 Xamarin 应用程序,它从数据库中检索信息,拍摄/选择照片并将它们上传到远程服务器,从远程服务器显示这些图像,用户可以通过点击并按下按钮来删除它们。 The final step is to download the images stored in the server to the local device gallery.最后一步是将存储在服务器中的图像下载到本地设备库。

This is my current button click event:这是我当前的按钮单击事件:

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");
        }
}

Below the webClient_DownloadDataCompleted method: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");
    }
}

But it does not work, no error caught, I get the alert which warn me that the download is completed.但它不起作用,没有发现错误,我收到警报,警告我下载已完成。 Also I gave permission for internet , write_external_storage and read_external_storage .我还允许internetwrite_external_storageread_external_storage

Another thing is that the images after some time, appears in the gallery under Download album which is correct.另一件事是,一段时间后,图像出现在“下载相册”下的图库中,这是正确的。

Any idea about this behavior?对这种行为有什么想法吗?

EDIT编辑

Below my new button download event:在我的新按钮下载事件下方:

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");
}

Causes原因

Your function "fires and forget" about the download and then directly shows you the "Download complete" popup.您的功能“触发并忘记”下载,然后直接向您显示“下载完成”弹出窗口。 The reaons are that you are calling asynchronous functions in a synchronous way ( DownloadDataAsync )... This is why it would still appear after a while in the gallery while you still get the pop up.原因是您以同步方式( DownloadDataAsync )调用异步函数......这就是为什么它会在一段时间后仍然出现在库中而您仍然会弹出。

Solutions解决方案

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

Then as a starting point, try with declaring your event handler async and use the await keyword at appropriate places:然后作为起点,尝试声明您的事件处理程序 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)
    {
        ...
    }
}

Of course it would be better to also refactor the other method using the async/await pattern all the way down, but this gives you a good starting point I guess.当然,最好也使用 async/await 模式重构另一种方法,但我想这为您提供了一个很好的起点。

EDIT:编辑:

Regarding the new method you edited, try using DownloadDataTaskAsync and CopyToAsync method along with async/await pattern:关于您编辑的新方法,请尝试使用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");
    }

Also, you should create a DisplayAlertAsync method and call it the same way using await.此外,您应该创建一个DisplayAlertAsync方法并使用 await 以相同的方式调用它。

Happy coding!快乐编码!

The image was downloaded correctly and I can see it in my file explorer.图像已正确下载,我可以在文件资源管理器中看到它。

I resolved my problem with a resfresh of the gallery, with this lines after saving my image, so the method will be:我通过重新刷新图库解决了我的问题,保存图像后使用此行,因此方法将是:

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");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM