0

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 and download the images from the remote server to the local device.

Everything works without problem, but when I download the image and after I go to the gallery for check it, the image does not appear, whereas I can see it and open in the file explorer. When I reboot the phone, the image appear in the gallery.

Below my current button download method:

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 = System.IO.Path.GetFileName(image_url_format.LocalPath);
        string dest_path = System.IO.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", "Download completed!", "OK");
}

I tried in another device, but I got the same behavior.

Probably there is a sort of thing which does not refresh the gallery.

Any idea how to force the gallery to refresh or something similar?

Leonardo Bassi
  • 184
  • 1
  • 2
  • 14
  • Your problem has been reported a hundred times so it should not be difficult to google the two code lines solution. You could also reboot your device. – blackapps Jan 28 '20 at 13:20
  • 1
    https://stackoverflow.com/questions/20150273/how-to-see-camera-app-take-photo-asynchronous-in-the-gallery/30095278#30095278 – Miamy Jan 28 '20 at 13:22
  • @blackapps Sorry but I do not find anything useful for my case, and I can not reboot my device every time that I download an image.. – Leonardo Bassi Jan 28 '20 at 13:24
  • No of course not. Its just an answer to your `Any idea how to force the gallery to refresh `. – blackapps Jan 28 '20 at 13:25

4 Answers4

1

You need to refresh your gallery after inserting or deleting any pictures in storage.

You can try this.

            var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
            mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(dest_path)));
            Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent);

Add these lines below your code. Make it like

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 = System.IO.Path.GetFileName(image_url_format.LocalPath);
    string dest_path = System.IO.Path.Combine(dest_folder, file_name);
    using (var fileStream = new FileStream(dest_path, FileMode.Create, FileAccess.Write))
    {
        image_stream.CopyTo(fileStream);
    }
    var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
    mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(dest_path)));
    //for old xamarin forms version
    Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent);
    //for new xamarin forms version
    //Android.App.Application.SendBroadcast(mediaScanIntent);
}
catch (Exception ex)
{
    DisplayAlert("Error", ex.ToString(), "OK");
    return;
}
    DisplayAlert("Alert", "Download completed!", "OK");  
}
Blu
  • 821
  • 4
  • 17
0

You need to just refresh the file you have downloaded. It's helpful.

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            File f = new File("file://"+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
            Uri contentUri = Uri.fromFile(f);
            mediaScanIntent.setData(contentUri);
            this.sendBroadcast(mediaScanIntent);
    }else{
            sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
    }
Nensi Kasundra
  • 1,980
  • 6
  • 21
  • 34
0

Make sure required permission given on both platforms.

Use in your class:

 bool success = await DependencyService.Get<IPhotoLibrary>().SavePhotoAsync(data, folder, filename);

Common Interface

  public interface IPhotoLibrary
    {
        Task<bool> SavePhotoAsync(byte[] data, string folder, string filename);
    }

In Android service

  public async Task<bool> SavePhotoAsync(byte[] data, string folder, string filename)
        {
            try
            {
                File picturesDirectory = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures);
                File folderDirectory = picturesDirectory;

                if (!string.IsNullOrEmpty(folder))
                {
                    folderDirectory = new File(picturesDirectory, folder);
                    folderDirectory.Mkdirs();
                }

                using (File bitmapFile = new File(folderDirectory, filename))
                {
                    bitmapFile.CreateNewFile();

                    using (FileOutputStream outputStream = new FileOutputStream(bitmapFile))
                    {
                        await outputStream.WriteAsync(data);
                    }

                    // Make sure it shows up in the Photos gallery promptly.
                    MediaScannerConnection.ScanFile(MainActivity.Instance,
                                                    new string[] { bitmapFile.Path },
                                                    new string[] { "image/png", "image/jpeg" }, null);
                }
            }
            catch (System.Exception ex)
            {
                return false;
            }

            return true;
        }

In iOS service:

public Task<bool> SavePhotoAsync(byte[] data, string folder, string filename)
        {
            NSData nsData = NSData.FromArray(data);
            UIImage image = new UIImage(nsData);
            TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();

            image.SaveToPhotosAlbum((UIImage img, NSError error) =>
            {
                taskCompletionSource.SetResult(error == null);
            });

            return taskCompletionSource.Task;
        }

also you can refer this one just to save an image and to reflect it in media, no need to use skiasharp for that. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/bitmaps/saving

Hope this may resolve your issue.

MShah
  • 1,247
  • 9
  • 14
0

Refer to Blu's answer,

I changed this Xamarin.Forms.Forms.Context.SendBroadcast(mediaScanIntent); to Android.App.Application.Context.SendBroadcast(mediaScanIntent); and all works.

Leonardo Bassi
  • 184
  • 1
  • 2
  • 14