Scan Android SD card for new files

后端 未结 6 1732
感情败类
感情败类 2020-11-27 19:59

My app allows a user to save an image to their SD card. But I\'m not sure how to make it appear in the gallery until you unmount and remount the SD card. I have googled for

相关标签:
6条回答
  • 2020-11-27 20:14

    You could also call media scanner explicitly by sending broadcast.

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

    Edit

    This was an old post. Updating it to new versions

    Android is taking steps to prevent apps from spoofing more system broadcasts like this.

    If you want to tell Android to index a file you put on external storage, either use MediaScannerConnection or ACTION_MEDIA_SCANNER_SCAN_FILE

    Reference: This post

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        final Uri contentUri = Uri.fromFile(outputFile); 
        scanIntent.setData(contentUri);
        sendBroadcast(scanIntent);
    } else {
        final Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));
        sendBroadcast(intent);
    }
    

    If the above piece of code is not working you can try the following:

    MediaScannerConnection.scanFile(this, new String[] {
        file.getAbsolutePath()
    }, null, new MediaScannerConnection.OnScanCompletedListener() {
    
        @Override
        public void onScanCompleted(String path, Uri uri) {
    
    
        }
    });
    
    0 讨论(0)
  • 2020-11-27 20:16

    I've tried plenty of different methods to trigger the MediaScanner, and these are my results.

    SendBroadcast

    The most simple and naive solution. It consists in executing the following instruction from your code:

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

    However, this no longer works in KitKat devices, due to a lack of required permissions.


    MediaScannerWrapper

    As posted here (per @Brian's answer), it consists in wrapping a MediaScannerConnection instance in order to trigger the scan() method over a specific directory. This method has proven to be working fine for 4.3 and below, but still no luck with KitKat (4.4+).


    FileWalker

    One of the many Play Store apps that tries to overcome the MediaStore's lack of commitment to update its database is ReScan SD. It sends a lot of different broadcasts:

      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file://" + Environment.getExternalStorageDirectory())));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable")));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable/SD")));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable/MicroSD")));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///mnt/Removable/MicroSD")));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///mnt")));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///storage")));
      sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable")));
    

    and tries to support KitKat by manually triggering the scan() method over each file of the base directory. Unfortunately, this is both very CPU-intensive and time-consuming, so it is not very recommended.


    "The shell way"

    The only thing that seem to work with KitKat in some cases is sending the broadcast via adb shell. So, this snippet allows you to do just that programmatically:

    Runtime.getRuntime().exec("am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://" + Environment.getExternalStorageDirectory());
    

    It is more of an hack-ish way of doing it, but at the moment is the best I could come up with.


    Bottom line

    Each of the above solutions actually works for everything that is not KitKat. That's because, thanks to Justin, a bug has been found and issued to the official Tracker. This means that, until the bug is ironed out, we are left with no true KitKat support.

    Which one to use? Among those, I would use the MediaScannerWrapper solution, together with the shell-ish approach (the last one).

    0 讨论(0)
  • 2020-11-27 20:16

    Since the last answer I posted apparently wasn't an appropriate method, I found another method here. You basically create a wrapper class, initialize it, and then call the scan() method. Very helpful post. Let me know if this isn't appropriate either.

    0 讨论(0)
  • 2020-11-27 20:23

    Here is another way to force scan:

    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,"uri to file"));
    

    And then system will fire ACTION_MEDIA_SCANNER_FINISHED broadcast so you can react on it with BroadcastReceiver

    In order to be able to receive ACTION_MEDIA_SCANNER_FINISHED broadcast, intent filter should contain data scheme:

    IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_FINISHED);
    intentFilter.addDataScheme("file");
    context.registerReceiver(mMediaScannerFinishReceiver, intentFilter);
    

    from the doc:

    public static final String ACTION_MEDIA_SCANNER_SCAN_FILE

    Added in API level 1 Broadcast Action: Request the media scanner to scan a file and add it to the media database. The path to the file is contained in the Intent.mData field.

    and

    public static final String ACTION_MEDIA_SCANNER_FINISHED

    Added in API level 1 Broadcast Action: The media scanner has finished scanning a directory. The path to the scanned directory is contained in the Intent.mData field.

    0 讨论(0)
  • 2020-11-27 20:24

    You can use MediaStore.Images.Media.insertImage to insert an item into the gallery.

    0 讨论(0)
  • 2020-11-27 20:29

    Use MediaScannerConnection:

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

    It can be a little bit of a pain because of the multiple levels of asynchronous calls, so as of API 8 (Froyo) there is a helper function:

    http://developer.android.com/reference/android/media/MediaScannerConnection.html#scanFile(android.content.Context, java.lang.String[], java.lang.String[], android.media.MediaScannerConnection.OnScanCompletedListener)

    0 讨论(0)
提交回复
热议问题