扫描Android SD卡以获取新文件

问题描述 投票:11回答:6

我的应用程序允许用户将图像保存到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 {
         ...
    }

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

android media sd-card android-mediascanner
6个回答
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和耗时的,因此不太推荐。


“贝壳方式”

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

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

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


底线

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

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


5
投票

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


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)


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) {


    }
});

0
投票

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


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

来自文档:

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字段中。

© www.soinside.com 2019 - 2024. All rights reserved.