15

I got this class:

import android.content.Context;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.util.Log;

public class MediaScannerWrapper implements  
MediaScannerConnection.MediaScannerConnectionClient {
    private MediaScannerConnection mConnection;
    private String mPath;
    private String mMimeType;


    // filePath - where to scan; 
    // mime type of media to scan i.e. "image/jpeg". 
    // use "*/*" for any media
    public MediaScannerWrapper(Context ctx, String filePath, String mime){
        mPath = "/sdcard/DCIM/Camera";
        mMimeType = "jpg";
        mConnection = new MediaScannerConnection(ctx, this);
    }

    // do the scanning
    public void scan() {
        mConnection.connect();
    }

    // start the scan when scanner is ready
    public void onMediaScannerConnected() {
        mConnection.scanFile(mPath, mMimeType);
        Log.w("MediaScannerWrapper", "media file scanned: " + mPath);
    }

    public void onScanCompleted(String path, Uri uri) {
        // when scan is completes, update media file tags
    }
}

How to use it in the other class? I don't know how to properly use classes, I tried but nothing is working. I do something wrong, but I don't know what, can someone help me with this.

Bigflow
  • 3,616
  • 5
  • 29
  • 52
  • 1
    Are you talking about [that post](http://stackoverflow.com/questions/4753252/scan-android-sd-card-for-new-files)? – XMoby Feb 23 '12 at 16:34
  • Oh, didn't found that post, thanks! – Bigflow Feb 24 '12 at 07:11
  • Could you still help me, I am really bad with classes and such things in Java. – Bigflow Feb 24 '12 at 07:42
  • What is it that you want to do exactly? – bluefalcon Feb 24 '12 at 11:04
  • With my program, I change the name of a picture, then when I try to open the image again (same app, without closing it) it doesn't reconize the picture anymore. However, after a mediascan, it does reconize it. So I want to scan a path or a file, so the app reconize the name change. – Bigflow Feb 24 '12 at 11:14
  • you will need to update the content database, see my answer below – bluefalcon Feb 24 '12 at 11:35
  • I won't go with a full Java and classes course, because there's already a lot of resources on the web for that. I don't mean to be rude; I just feel you'll get better documentation by reading full-fledged tutorials and how-to's. That said, in your case, just make sure you instantiate your helper class in your code path, then call the scan method on the instance. Something like that: MediaScannerWrapper myScanner = new MediaScannerWrapper(); myScanner.scan(); – XMoby Feb 24 '12 at 13:48

6 Answers6

52

The Story

Before Android 4.4, we could just send a broadcast to trigger the media scanner on any particular file, or folder or even on the root of the storage. But from 4.4 KitKat, this have been fixed by the Android Developers.

Why do I say fixed? The reason is simple. Sending a broadcast using MEDIA_MOUNTED on the root directory is very expensive. Running the Media Scanner is an expensive operation and the situation gets even worse when the user has got a lot of files in the storage and deep folder structures.

Before Android 4.4

Keep it straight and simple. If you are targeting your app before Android 4.4. But keep in mind not to use it on the root directory unless absolutely necessary.

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));

From Android 4.4

There are two ways for you.

i) The first one is very similar to the previous example, but may not work efficiently and is not recommended too.

sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory())));

ii) Now, let us move on to the most recommended and efficient solution to this problem.

Add the file paths of the files which have been updated, like this, in a String type ArrayList

ArrayList<String> toBeScanned = new ArrayList<String>();
toBeScanned.add(item.getFilePath());

Now you need to run scanFile() static method of the MediaScannerConnection class and pass the String array containing the list of all the files which have been updated and needs to be media scanned.

You can also put a listener to respond when the scanning has been finished for individual files.

String[] toBeScannedStr = new String[toBeScanned.size()];
                toBeScannedStr = toBeScanned.toArray(toBeScannedStr);

                MediaScannerConnection.scanFile(getActivity(), toBeScannedStr, null, new OnScanCompletedListener() {

                    @Override
                    public void onScanCompleted(String path, Uri uri) {
                        System.out.println("SCAN COMPLETED: " + path);

                    }
                });
Aritra Roy
  • 15,355
  • 10
  • 73
  • 107
  • 1
    way ii converts directories into files, see http://stackoverflow.com/questions/31157882/mediascannerconnectionscanfile-converts-directories-into-files-when-accessing-t – OneWorld Jul 01 '15 at 09:48
  • 2
    way i has no effect (both comments refer to Android 5) – OneWorld Jul 01 '15 at 10:02
  • When I copy a file to the Ringtones folder, and let Media Scanner scan it, it shows up right away on the sound picker ! However, after I have my app delete the file from the Ringtones folder, I also let media scanner scan it (`onScanCompleted()` triggers with uri = null), yet, media picker **still** shows that file. What to do after deleting the file so that media picker no longer shows it ? – Someone Somewhere Dec 21 '15 at 15:38
  • Can't we just put the path of the file directly to Intent.ACTION_MEDIA_SCANNER_SCAN_FILE or Intent.ACTION_MEDIA_MOUNTED? So it will be like sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(filePath))); – HendraWD Jun 15 '16 at 05:47
  • 1
    this should be the more appropriate answer instead of the accepted answer below, as the accepted answer does not scan **on specific path**, +1 – am05mhz Jun 25 '16 at 02:24
  • @Aritra Roy I am creating a gallery app. And In that app whenever a user renames a folder, I want mediascanner to scan and remove earlier album and add new album. So any best way to do this. And can I give Uri of a folder to sendBroadcast. – Ankesh kumar Jaisansaria Aug 27 '16 at 10:28
  • @AnkeshkumarJaisansaria Have you followed this method? – Aritra Roy Aug 27 '16 at 13:07
  • Yes but not able to refresh media store – Ankesh kumar Jaisansaria Aug 27 '16 at 13:16
  • @AnkeshkumarJaisansaria I have just tried the exact same thing for 4.4, works like a charm. – Aritra Roy Aug 27 '16 at 15:00
  • @Aritra Roy Passing file uri is working but I want to pass Folder Uri as the whole folder name has changed – Ankesh kumar Jaisansaria Aug 28 '16 at 07:33
  • Please help for Triggering media scan on folder – Ankesh kumar Jaisansaria Aug 28 '16 at 14:57
  • You can just loop through the files inside the folder and pass each of them to be scanned. Have tried it now, and its working for me. – Aritra Roy Aug 28 '16 at 14:59
  • MediaScannerConnection.scanFile used to work previously, but for unknown reason, that's doesn't work anymore on my device, so i had to change to Intent.ACTION_MEDIA_SCANNER_SCAN_FILE – HendraWD Sep 08 '16 at 07:22
  • MediaScannerConnection.ScanFile works for me, but _only_ if I also add the parent directory in the String array. See also http://stackoverflow.com/a/31497971/911550 – parvus Oct 19 '16 at 12:34
  • but how to use it for empty directories? Use the "not recommended" method? – Janeks Bergs Dec 15 '16 at 22:20
  • 1
    ii) - didn't work on Android 7, Nexus 5x: sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uriToMyDir)); The folder was in the root of internal memory. Only approach with scanFile helped. – Kirill Karmazin Mar 03 '17 at 10:05
10

Hey I found out how to do it with a very simple code.

Just call this line of code:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));

This should trigger mediascanner.

Bigflow
  • 3,616
  • 5
  • 29
  • 52
  • 5
    It will trigger the mediascanner but it will scan the all the files (except those folder with .nomedia file) in the SD Card. It will take time to scan depending on the no of files in your sd card. – artsylar Apr 16 '12 at 05:28
  • 4
    Intent.ACTION_MEDIA_MOUNTED will break on Android 4.4+ devices as the intent is now limited to system applications. – Nj Subedi Jan 17 '15 at 09:44
  • `Permission Denial: not allowed to send broadcast android.intent.action.MEDIA_MOUNTED` – Pratik Butani May 06 '20 at 14:34
7

In Android, there is a content database which is used by the media scanner to keep track of all the media content present on the device.

When Android boots up, the mediascanner service is launched and runs through the entire external storage to find if there is any new media content if it finds one then,

  • It adds an entry of that media content into the content database
  • Each entry in the content database contains metadata of the media content like Name, date, file size, type of file, etc..
  • So when you make a modification to a media content, you will need to update the content database also.
  • If the content database is not update then other applications also will not be able to access that particular media content.
  • Running the media scanner just updates the content database

Instead of running the media scanner, you can update the content database yourself and it should resolve the problem.

Here is an explanation on how to insert, delete, update using the content resolver. (Search for the section "Inserting, Updating, and Deleting Data")

Edit: There is a sample code in this answer. Check for the answer by Janusz.

Community
  • 1
  • 1
bluefalcon
  • 4,225
  • 1
  • 32
  • 41
6
   File file = new File(absolutePath);
   Uri uri = Uri.fromFile(file);
   Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
   sendBroadcast(intent);
abhi5306
  • 134
  • 1
  • 7
1
private void galleryAddPic() {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}

Reference: http://developer.android.com/training/camera/photobasics.html#TaskGallery

The Add the Photo to a Gallery Section

Loyea
  • 3,359
  • 1
  • 18
  • 19
0

As @Aritra Roy's answer, i decide to make an experiment about this issue. What i got here are:

  • Intent.ACTION_MEDIA_MOUNTED and Intent.ACTION_MEDIA_SCANNER_SCAN_FILE can accept individual file path, so sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(filePath))); or sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse(filePath))); will be valid.
  • If you use individual file path with Intent.ACTION_MEDIA_MOUNTED on Kitkat or above, your application will still crash
  • If you use Intent.ACTION_MEDIA_SCANNER_SCAN_FILE or MediaScannerConnection on device lower than Kitkat, your application will not force close, but the method will just simply not working as you want.

From that experiment, i think the best method to handle is

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    MediaScannerConnection.scanFile(context, new String[]{imagePath}, null, new MediaScannerConnection.OnScanCompletedListener() {
        public void onScanCompleted(String path, Uri uri) {
            //something that you want to do
        }
    });
} else {
    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
            Uri.parse("file://" + imagePath)));
}

Let me know if i missed something

HendraWD
  • 2,984
  • 2
  • 31
  • 45