12

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

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

4

6 回答 6

9

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

发送广播

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

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

但是,由于缺少所需的权限,这不再适用于 KitKat 设备。


MediaScannerWrapper

正如此处发布的(根据@Brian 的回答),它包括包装一个MediaScannerConnection实例以在scan()特定目录上触发该方法。这种方法已被证明适用于 4.3 及以下版本,但在 KitKat (4.4+) 上仍然没有运气。


文件行者

试图克服 MediaStore 缺乏更新其数据库的承诺的众多 Play Store 应用程序之一是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,我们发现了一个错误并发布给了官方 Tracker。这意味着,在解决该错误之前,我们将无法获得真正的 KitKat 支持。

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

于 2014-04-15T08:28:36.900 回答
5

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

于 2011-01-24T22:32:30.877 回答
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)

于 2011-01-21T01:57:56.863 回答
3

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

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

编辑

这是一个旧帖子。将其更新到新版本

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

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

参考:这篇文章

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


    }
});
于 2013-08-20T07:31:14.320 回答
1

是另一种强制扫描的方法:

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

来自文档:

公共静态最终字符串 ACTION_MEDIA_SCANNER_SCAN_FILE

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

公共静态最终字符串 ACTION_MEDIA_SCANNER_FINISHED

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

于 2014-02-25T12:04:59.023 回答
0

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

于 2011-01-20T22:25:58.033 回答