扫描Android SD卡以获取新文件

时间:2011-01-20 22:13:02

标签: android media sd-card android-mediascanner

我的应用允许用户将图像保存到SD卡。但是我不知道如何卸下并重新安装SD卡之前如何让它出现在画廊中。我已经用Google搜索了几天这个问题,但我不确定如何让它自动出现。我发现 this链接,但我不确定如何使用该类。这是我用来保存文件。在try catch块的底部是我想要扫描sd卡以获取新媒体的地方。

    FileOutputStream outStream = null;
    File file = new File(dirPath, fileName);
    try {
        outStream = new FileOutputStream(file);
        bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
        outStream.flush();
        outStream.close();
    } catch {
         ...
    }

如果有人能指出我正确的方向,我将不胜感激。

6 个答案:

答案 0 :(得分:9)

我尝试了很多不同的方法来触发MediaScanner,这些都是我的结果。

<强> SendBroadcast

最简单,最天真的解决方案。它包括执行代码中的以下指令:

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

但是,由于缺少必要的权限,KitKat设备中不再有效


<强> MediaScannerWrapper

发布here(根据@ Brian的答案),它包含一个MediaScannerConnection实例,以便在特定目录上触发scan()方法。事实证明这种方法在4.3及以下版本中工作正常,但KitKat(4.4 +)仍然没有运气。


<强> FileWalker

试图克服MediaStore缺乏更新数据库承诺的众多Play商店应用中的一个是ReScan SD。它发送了许多不同的广播:

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

并尝试通过在基本目录的每个文件上手动触发scan()方法来支持KitKat。不幸的是,这是非常耗费CPU和耗时的,因此不太推荐。


&#34; shell方式&#34;

在某些情况下,唯一可以与KitKat配合使用的是通过adb shell发送广播。因此,此代码段允许您以编程方式执行此操作:

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

这更像是一种黑客行为方式,但目前是我能想到的最佳方式。


底线

上述每个解决方案实际上适用于所有不是KitKat的解决方案。这是因为,感谢Justin,我们找到了一个错误并发给了official Tracker。这意味着,在消除错误之前,我们没有真正的KitKat支持。

使用哪一个?其中,我会使用MediaScannerWrapper解决方案和shell-ish方法(最后一个)。

答案 1 :(得分:5)

由于我发布的最后一个答案显然不是一个合适的方法,我找到了另一种方法here。您基本上创建一个包装类,初始化它,然后调用scan()方法。非常有用的帖子。如果这也不合适,请告诉我。

答案 2 :(得分:3)

使用MediaScannerConnection:

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

由于多级异步调用,这可能有点痛苦,因此API 8(Froyo)中有一个辅助函数:

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

答案 3 :(得分:2)

您也可以通过发送广播来明确调用媒体扫描程序。

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

修改

这是一篇旧帖子。将其更新为新版本

Android正在采取措施防止应用欺骗更多像这样的系统广播。

如果您想告诉Android索引您放在外部存储上的文件,请使用MediaScannerConnectionACTION_MEDIA_SCANNER_SCAN_FILE

参考: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);
}

如果上面的代码不起作用,您可以尝试以下方法:

MediaScannerConnection.scanFile(this, new String[] {
    file.getAbsolutePath()
}, null, new MediaScannerConnection.OnScanCompletedListener() {

    @Override
    public void onScanCompleted(String path, Uri uri) {


    }
});

答案 4 :(得分:0)

您可以使用MediaStore.Images.Media.insertImage将项目插入图库。

答案 5 :(得分:0)

Here是强制扫描的另一种方式:

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

然后系统将触发ACTION_MEDIA_SCANNER_FINISHED广播,以便您可以使用BroadcastReceiver做出反应

为了能够接收ACTION_MEDIA_SCANNER_FINISHED广播,意图过滤器应该包含数据方案:

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

来自doc:

  

public static final String ACTION_MEDIA_SCANNER_SCAN_FILE

     

在API级别1中添加广播操作:请求媒体扫描程序   扫描文件并将其添加到媒体数据库。该文件的路径是   包含在Intent.mData字段中。

  

public static final String ACTION_MEDIA_SCANNER_FINISHED

     

在API级别1中添加广播操作:媒体扫描程序已完成   扫描目录。包含扫描目录的路径   在Intent.mData字段中。