扫描 Android SD 卡以获取新文件

Posted

技术标签:

【中文标题】扫描 Android SD 卡以获取新文件【英文标题】:Scan Android SD card for new files 【发布时间】:2011-06-12 19:13:13 【问题描述】:

我的应用允许用户将图像保存到他们的 SD 卡。但是在您卸载并重新安装 SD 卡之前,我不确定如何让它出现在图库中。我已经用谷歌搜索了几天这个问题,但不知道如何让它自动出现。我发现 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 
         ...
    

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

【问题讨论】:

“sdrescan”应用程序可以满足您的需求。免费;也许您可以向作者索要代码sn-p。或者只是从您的应用中启动它。 有没有办法在不停止音乐播放器的情况下重新扫描?它说对不起,媒体播放器不支持这个文件,直到我按下一首曲目,向前一首曲目,然后再次播放。 【参考方案1】:

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

发送广播

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

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 发送广播。因此,这个 sn-p 允许您以编程方式执行此操作:

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

这更像是一种hack-ish方式,但目前是我能想到的最好的方式。


底线

上述每个解决方案实际上都适用于不是 KitKat 的所有东西。这是因为,感谢Justin,发现了一个错误并将其发布给official Tracker。这意味着,在解决该错误之前,我们将无法获得真正的 KitKat 支持。

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

【讨论】:

KITKAT 上的 shell 方法你提到它在某些情况下有效。我很想知道这种方法在哪个用例下失败?或者它在哪些用例下有效? 我找不到任何固定用例。唯一可行的方法是在添加文件后刷新 MediaScanner。另一方面,当文件被删除时它不起作用。 当我使用 adb shell 从命令行发送广播时,它适用于新文件和已删除文件。但它不能在 KitKat 上以编程方式处理新文件或删除文件。我正在测试音频音乐文件并使用模拟器 API 19。 我认为这是可以做到的。因为当我重命名或添加一些媒体文件,然后使用 ES 文件资源管理器并更改包含该媒体的文件夹的路径时,它们会出现在图库中并添加到媒体存储中,如果您有很多媒体,则需要一些时间来重新生成缩略图在那个文件夹上。顺便说一下,当我添加或重命名图像文件时,我会查看 logcat:Media Provider object removed 然后是一些带有标签art 的 logcat 关于 crating bitmap,我确信这样做的唯一方法是使用新数据和位图更新 MediaStore 和如果您重命名或移动媒体,请删除最后一个并添加新媒体。【参考方案2】:

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

【讨论】:

注意:这使用从 API 级别 1 开始可用的 scanFile()。而不是 API 级别 8 之后可用的较新的 scanFile()。【参考方案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)

【讨论】:

我已经阅读了好几遍参考资料,但我不知道如何让 mediaScannerConnection 工作。至于辅助功能,我认为这还不是最好的方法。 API 8 不是很旧,很多设备(包括我的测试手机)都不支持它。我用我最初帖子中的链接玩了几天,但我无法让那个例子工作。如果您可以发布一些 sn-ps 或指向另一个示例,我将不胜感激。在那之前,我将不得不保留“sendBroadcast”方法,因为它是现在唯一有效的方法。 这里有一个新函数的 API 演示:developer.android.com/resources/samples/ApiDemos/src/com/… 您可以在此处找到该函数为您自己的实现建模的代码实现:android.git.kernel.org/?p=platform/frameworks/… 重申:请勿发送 ACTION_MEDIA_MOUNTED。这将做所有的事情,包括对 SD 卡的完整扫描。事实上,我需要确保在未来版本的平台应用程序中无法发送它,因为如果他们在错误的时间获取它,可能会导致平台的某些部分行为异常。因此,如果您这样做是为了让您的应用程序崩溃,请期待将来。 就像我说的,我想改变它并以正确的方式去做。但我无法以“正确的方式”工作。如果您能帮助我告诉我该做什么而不是告诉我不该做什么,我将不胜感激。 @hackbod - 我发现让 mediastore 扫描已删除照片的唯一方法是使用 ACTION_MEDIA_MOUNTED。我尝试了几种解决方案,但都失败了:MediaScannerConnection.scanFile(...) with file and parent。 ACTION_MEDIA_SCANNER_SCAN_FILE 也无法正常工作。【参考方案4】:

您也可以通过发送广播显式调用媒体扫描器。

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) 


    
);

【讨论】:

不允许发送广播android.intent.action.MEDIA_MOUNTED【参考方案5】:

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

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

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

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

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

来自文档:

公共静态最终字符串 ACTION_MEDIA_SCANNER_SCAN_FILE

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

公共静态最终字符串 ACTION_MEDIA_SCANNER_FINISHED

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

【讨论】:

【参考方案6】:

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

【讨论】:

感谢您的帮助。但我无法让“insertImage”工作。不过我在另一个论坛上找到了答案。

以上是关于扫描 Android SD 卡以获取新文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SD 卡以 48 ksamples/s 记录 16 位数据?

android中扫描模拟器sd卡中mp3后缀的所有音乐文件,并显示到listView中,求源码或实现方法?

android如何实现扫描sd卡图片,并统计图片个数

Android - 如何使用新的存储访问框架将文件复制到外部 sd 卡

microlog4android如何将Android Log日志写到SD

如何在android中获取存储在sd卡中的文件名