97

I save an image to the sdcard and it doesn't appear in the Gallery application until I pull off the sdcard and return it back.

Do you have any idea why is it so?

Seems like the Gallery application has some cache that isn't updated on file save...

Actually, I also want to open the just-saved image in Gallery application and have no success with that
this is my question about this issue.

Community
  • 1
  • 1
Michael Kessler
  • 14,245
  • 13
  • 50
  • 64
  • 1
    This question has been answered step by step in this tutorial : http://stackoverflow.com/questions/30506301/app-crashes-when-loading-image-from-gallery/30507641#30507641 – Takermania May 28 '15 at 13:19

17 Answers17

93

A simpler solution is to use the static convenience method scanFile():

File imageFile = ...
MediaScannerConnection.scanFile(this, new String[] { imageFile.getPath() }, new String[] { "image/jpeg" }, null);

where this is your activity (or whatever context), the mime-type is only necessary if you are using non-standard file extensions and the null is for the optional callback (which we don't need for such a simple case).

darrenp
  • 4,265
  • 2
  • 26
  • 22
  • 2
    Spot on, the broadcast method that others (and google) provide, very rarely works). – Chris.Jenkins Nov 18 '13 at 13:56
  • 2
    This was working for me in earlier android versions ~4.0 but now in 4.3+ doesn't seem to be working. The images aren't showing up in the gallery app. – hooby3dfx Mar 01 '14 at 19:50
  • Perfect ! You can get context with : Android.App.Application.Context – jug Aug 12 '16 at 08:24
  • Worked in marshmallow – Hitesh Sahu Jan 11 '17 at 04:24
  • Works on Kitkat, works on Pie. The only thing I don't get is why my toast isn't showing in the `OnScanCompletedListener` callback. I invoke `Log.i()` and `Toast.makeText().show()`, but only logging takes effect, there is no toast. I'm out of ideas. – bighugedev Aug 29 '23 at 02:04
67

My answer to the original question and to anyone else that may have this problem:

I was having this same problem, images in my app that people saved to the SD card were not showing up in their Gallery immediately. After some searching I found this one line of code inserted after my 'save to sdcard' code that fixed the problem:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
ShadowGod
  • 7,891
  • 3
  • 28
  • 31
  • do we need to use media scanner to be able to use this broadcast? i am using anothermethod to display images in my gallery. When i am using above sendBroadcast on save button click my gallery is not updated with the new image! – change Nov 10 '12 at 01:42
  • 4
    It's old but this may help someone - a more specific path: sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)))); This method (this answer, not only my comment) doesn't work on the emulator. Test on real device. –  Apr 11 '13 at 16:19
  • I believe the accepted answer offers the correct way to do it. But if you are trying to support API <= 7 then this is a nice fallback. – Amr Mostafa Nov 16 '13 at 19:04
  • Your answer is helpful for other devices. It's not working on HTC, When I try to scan my Application folder. It doesn't show up newly added image. – MobileEvangelist Nov 20 '13 at 06:53
  • 7
    This seems to be no longer supported on Android 4.4 or greater. A permission exception will be thrown in this case. – rsp1984 Jan 24 '14 at 18:44
  • this does not work on KITKAT. What is the workaround for this on KITKAT? – Muhammad Riyaz Mar 14 '14 at 11:43
  • This no longer works !!! Coz android has made this broadcast private with the release of KITKAT . i.e broadcast with intent Intent.ACTION_MEDIA_MOUNTED is protected now. – lakshay Apr 13 '15 at 10:21
46

The system scans the SD card when it is mounted to find any new image (and other) files. If you are programmatically adding a file, then you can use this class:

http://developer.android.com/reference/android/media/MediaScannerConnection.html

hackbod
  • 90,665
  • 16
  • 140
  • 154
  • 5
    Side note: Though the question refers to file addition, the MediaScannerConnection doesn't provide a solution for file deletion - not even when requesting to scan the parent folder of a deleted file. – AlikElzin-kilaka Sep 16 '13 at 08:18
13

Gallery refresh including Android KITKAT

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())));
}
AtanuCSE
  • 8,832
  • 14
  • 74
  • 112
  • The code which is inside the first condition whitin "IF" statement works fine for me in KitKat (Android 4.4.4, API 19). – Alex Dec 01 '16 at 13:48
13

You can also add an Image to the Media Gallery by intent, have a look at the example code to see how it is done:

ContentValues image = new ContentValues();

image.put(Images.Media.TITLE, imageTitle);
image.put(Images.Media.DISPLAY_NAME, imageDisplayName);
image.put(Images.Media.DESCRIPTION, imageDescription);
image.put(Images.Media.DATE_ADDED, dateTaken);
image.put(Images.Media.DATE_TAKEN, dateTaken);
image.put(Images.Media.DATE_MODIFIED, dateTaken);
image.put(Images.Media.MIME_TYPE, "image/png");
image.put(Images.Media.ORIENTATION, 0);

 File parent = imageFile.getParentFile();
 String path = parent.toString().toLowerCase();
 String name = parent.getName().toLowerCase();
 image.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
 image.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, name);
 image.put(Images.Media.SIZE, imageFile.length());

 image.put(Images.Media.DATA, imageFile.getAbsolutePath());

 Uri result = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);
Matt McMinn
  • 15,983
  • 17
  • 62
  • 77
Janusz
  • 187,060
  • 113
  • 301
  • 369
  • Hi. This method adds the image to the MediaStore, i have confirmed it by checking the returned `Uri` but the problem is that the inserted image is not showing in the gallery. I have checked both in the beginning and at the end of the gallery. Can you please suggest any method so that the inserted image should show in the gallery immediately? – Shajeel Afzal Mar 15 '15 at 16:07
8

Here is the code for the MediaScannerConnection:

MyMediaConnectorClient client = new MyMediaConnectorClient(newfile);
MediaScannerConnection scanner = new MediaScannerConnection(context, client);
client.setScanner(scanner);
scanner.connect();

newfile is the File object of your new/saved file.

3dmg
  • 718
  • 1
  • 9
  • 19
  • 3
    Thank you for your answer. Actually, I've already finished this project long time ago... I don't even remember what was the solution that I've used. Other users might find your solution helpful if you'd also provide the implementation of `MyMediaConnectorClient`... – Michael Kessler Mar 08 '10 at 11:33
  • yes - i'm having real headaches with this at the moment. Please post up :) – Steve Mar 31 '10 at 15:31
  • Yes I'm not really clear about how the flow should be -Correct me where I am wrong I can use MediaScannerConnection to update the SDCAARD info so I take picture with camera and pass the new file into the MSC and now I can access the file with with a connection scanner client? – Steve Mar 31 '10 at 18:02
  • The flow is: you take a picture, save it to your sdcard and then make the scanner update, so that the filesystem gets updated to see your saved pic in the device gallery. If you dont do that with the scanner, you see your pic after the next device restart in the gallery. – 3dmg Apr 01 '10 at 14:33
7

there is an app in the emulator that says - ' Dev Tools'

click on that and select ' Media Scanning'.. all the images ll get scanned

Abhishek Susarla
  • 578
  • 1
  • 6
  • 12
6

this work with me

File file = ..... // Save file

context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
user3245604
  • 79
  • 1
  • 6
6

Let your activity implement 'MediaScannerConnectionClient' and add this to your activity:

private void startScan() 
{ 
    if(conn!=null) conn.disconnect();  
    conn = new MediaScannerConnection(YourActivity.this,YourActivity.this); 
    conn.connect(); 
} 

@Override 
public void onMediaScannerConnected() { 
    try{
        conn.scanFile(yourImagePath, "image/*");
       } catch (java.lang.IllegalStateException e){
       }
}

@Override 
public void onScanCompleted(String path, Uri uri) { 
    conn.disconnect(); 
} 
TOMKA
  • 1,096
  • 13
  • 24
5
File folderGIF = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/newgif2"); // path where gif will be stored
boolean success = folderGIF.mkdir(); // make directory
String finalPath = folderGIF + "/test1.gif"; // path of file
.....
/* changes in gallery app if any changes in done*/
MediaScannerConnection.scanFile(this,
                    new String[] {
                        finalPath
                    }, null,
                    new MediaScannerConnection.OnScanCompletedListener() {
                        public void onScanCompleted(String path, Uri uri) {
                            Log.i("ExternalStorage", "Scanned " + path + ":");
                            Log.i("ExternalStorage", "-> uri=" + uri);
                        }
                    });
bighugedev
  • 379
  • 1
  • 3
  • 11
Khyati Vara
  • 1,042
  • 13
  • 22
  • I want to save animated gif file which is located in external storage and I have the path i.e. /storage/emulated/0/Android/data//files//xyz.gif. Now I want to Save/copy this file to Image Gallery and show there. How to do this. – Zia Ur Rahman Jul 18 '18 at 09:00
4
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

Does not seem to work on KITKAT. It throws permission denial exception and crashes the app. So for this, I have done the following,

String path = mediaStorageDir.getPath() + File.separator
                    + "IMG_Some_name.jpg";
CameraActivity.this.sendBroadcast(new Intent(
                             Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri
                            .parse("file://" + path)));

Hope it helps.

Muhammad Riyaz
  • 2,832
  • 2
  • 26
  • 30
3

Here I am sharing code that can load an image in the form of a bitmap and save that image on sdcard gallery in app name folder. You should follow these steps:

  1. Download Image Bitmap first
 private Bitmap loadBitmap(String url) {
     try {
         InputStream in = new java.net.URL(url).openStream();
         return BitmapFactory.decodeStream(in);
     } catch (Exception e) {
         e.printStackTrace();
     }
     return null;
 }
  1. Please also provide following permission in your AndroidManifest.xml file.
uses-permission android:name="android.permission.INTERNET" />
uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  1. Here is the whole code that is written for Activity in which we want to perform this task.
void saveMyImage(String appName, String imageUrl, String imageName) {
    Bitmap bmImg = loadBitmap(imageUrl);
    File filename;
    try {
        String path1 = android.os.Environment.getExternalStorageDirectory().toString();
        File file = new File(path1 + "/" + appName);
        if (!file.exists())
            file.mkdirs();
        filename = new File(file.getAbsolutePath() + "/" + imageName +
            ".jpg");
        FileOutputStream out = new FileOutputStream(filename);
        bmImg.compress(Bitmap.CompressFormat.JPEG, 90, out);
        out.flush();
        out.close();
        ContentValues image = new ContentValues();
        image.put(Images.Media.TITLE, appName);
        image.put(Images.Media.DISPLAY_NAME, imageName);
        image.put(Images.Media.DESCRIPTION, "App Image");
        image.put(Images.Media.DATE_ADDED, System.currentTimeMillis());
        image.put(Images.Media.MIME_TYPE, "image/jpg");
        image.put(Images.Media.ORIENTATION, 0);
        File parent = filename.getParentFile();
        image.put(Images.ImageColumns.BUCKET_ID, parent.toString()
            .toLowerCase().hashCode());
        image.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, parent.getName()
            .toLowerCase());
        image.put(Images.Media.SIZE, filename.length());
        image.put(Images.Media.DATA, filename.getAbsolutePath());
        Uri result = getContentResolver().insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);
        Toast.makeText(getApplicationContext(),
            "File is Saved in  " + filename, Toast.LENGTH_SHORT).show();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Hope that it can solve your whole problem.

bighugedev
  • 379
  • 1
  • 3
  • 11
2

Use this after saving the image

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
andrewsi
  • 10,807
  • 132
  • 35
  • 51
Deepu
  • 333
  • 1
  • 4
  • 15
  • 3
    This works but it's not the best solution. You are tricking the system into thinking the SD card would be (re-)mounted and possibly forcing rescanning the whole SD card. MediaScanner.scanFile(..) is the best solution when you now the file you want to add. – pocmo Oct 04 '12 at 15:13
  • 2
    This search for all the images. And it involves a lot of unnecessary data processing that may be irrelevant when we have just single image to be shown up in gallery. – Rahul Rastogi Aug 21 '14 at 06:02
2

My code for MyMediaConnectorClient:

public class MyMediaConnectorClient implements MediaScannerConnectionClient {

    String _fisier;
    MediaScannerConnection MEDIA_SCANNER_CONNECTION;

    public MyMediaConnectorClient(String nume) {
        _fisier = nume;
    }

    public void setScanner(MediaScannerConnection msc){
        MEDIA_SCANNER_CONNECTION = msc;
    }

    @Override
    public void onMediaScannerConnected() {
        MEDIA_SCANNER_CONNECTION.scanFile(_fisier, null);
    }

    @Override
    public void onScanCompleted(String path, Uri uri) {
        if(path.equals(_fisier))
            MEDIA_SCANNER_CONNECTION.disconnect();
    }
}
Raghav Satyadev
  • 728
  • 2
  • 11
  • 38
Marian
  • 21
  • 1
0

You need to give permissions to the Gallery app. Just long press the gallery app icon in the home screen and tap on 'APP INFO' that pops up at the top of the screen. Doing it will show the gallery app settings. Now go in Permissions tab and enable the storage, camera permissions by toggling it. Now go to your native gallery app and you will get the your saved images.

0

This will aslo solve your problem if your image in gallery are not showing instead they might showing a 404 type bitmap in midle. please add a the tags that are in my code with your image because there must some meta data in order to show image in gallery.

      String resultPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES)+ 
      getString(R.string.directory) + System.currentTimeMillis() + ".jpg";

       new File(resultPath).getParentFile().mkdir();

        try {
            OutputStream fileOutputStream = new FileOutputStream(resultPath);
            savedBitmap.compress(CompressFormat.JPEG, 100, fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        } catch (IOException e2) {
            e2.printStackTrace();
        }
        savedBitmap.recycle();

        File file = new File(resultPath);
        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE, "Photo");
        values.put(MediaStore.Images.Media.DESCRIPTION, "Edited");
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis ());
        values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
        values.put(MediaStore.Images.ImageColumns.BUCKET_ID, file.toString().toLowerCase(Locale.US).hashCode());
        values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, file.getName().toLowerCase(Locale.US));
        values.put("_data", resultPath);

        ContentResolver cr = getContentResolver();
        cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);




        return  resultPath;
Mubashir Murtaza
  • 327
  • 2
  • 14
0

Try this one, it will broadcast about a new image created, so your image becomes visible inside Gallery.

Replace photoFile with the actual file path of the newly created image.

private void galleryAddPicBroadCast() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    Uri contentUri = Uri.fromFile(photoFile);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}
bighugedev
  • 379
  • 1
  • 3
  • 11
Anand Saggam
  • 57
  • 1
  • 8