安卓如何使用MediaScannerConnection扫描文件

53

我正在将图片添加到SD卡上的文件夹中。由于这些图片和我的文件夹在图库中不会立即显示,因此我尝试使用MediaScannerConnection更新并在图库中显示文件夹/图片。

对我来说,这样做效果不太好,因为在图库中没有任何显示。我只是在Eclipse AVD中进行测试。

我没看到有关此方面的讨论,也许是因为自API8以来scanFile是新功能。有人能展示如何完成吗?

我正在尝试在服务和活动中执行此操作,但在onScanCompleted时仍然得到uri=null。


8个回答

109

我意识到你可能正在寻找一个适用于API 8版本之前的解决方案,而且我无法理解Mitch的答案。我通过构建一个用于扫描单个文件的类来解决了这个问题:

import java.io.File;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;

public class SingleMediaScanner implements MediaScannerConnectionClient {

    private MediaScannerConnection mMs;
    private File mFile;

    public SingleMediaScanner(Context context, File f) {
        mFile = f;
        mMs = new MediaScannerConnection(context, this);
        mMs.connect();
    }

    @Override
    public void onMediaScannerConnected() {
        mMs.scanFile(mFile.getAbsolutePath(), null);
    }

    @Override
    public void onScanCompleted(String path, Uri uri) {
        mMs.disconnect();
    }

}

使用以下方式,可以让MediaScannerConnection扫描单个文件:

new SingleMediaScanner(this, file);

媒体扫描器连接后就一直停在那里,这个过程应该需要多长时间? - hunterp
@Petrus,这个很好用。谢谢。但是我遇到了一个问题。在我的应用程序中,我捕获了一系列的图像。但最终只显示扫描完成后的第二张图片。你能告诉我可能出了什么问题吗? - AnujAroshA
1
请问为什么我们需要每次都初始化一个新的MediaScannerConnection,连接它,执行scanFile然后再断开连接呢?我尝试直接使用静态方法调用MediaScannerConnection.scanFile,而不进行这些操作也可以工作。更新:好吧,我问得太早了,所以静态方法只适用于API > 8,谢谢! - Bruce
同样在Android 6 Marshmallow上也能正常工作。谢谢。 - Taifun
有用的解决方案! - Hassan Jamil

84

我也在寻找同样的东西,然后我在 ApiDemos 的 ExternalStorage 中找到了这个。它解决了我所有的问题,因为它可以扫描单个文件。

 MediaScannerConnection.scanFile(this,
          new String[] { file.toString() }, null,
          new MediaScannerConnection.OnScanCompletedListener() {
      public void onScanCompleted(String path, Uri uri) {
          Log.i("ExternalStorage", "Scanned " + path + ":");
          Log.i("ExternalStorage", "-> uri=" + uri);
      }
 });

4
仅存在于API级别8及以上。 - Ivan G.
2
添加单个文件的最佳解决方案。 - leoly
2
运行起来非常顺畅,对于多个文件,可以手动将文件路径添加到字符串数组中。 - Diljeet
@Samidh T 实际上它在KitKat上运行良好,但我的情况比较棘手。我正在重命名一堆照片。添加照片和视频就像上面的代码一样简单。 - M. Reza Nasirloo
4
在Android 7.1 API 25模拟器上,Uri不为空且路径正确,但图像在相册中无法显示。 - dakshbhatt21
显示剩余6条评论

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

2
我现在已经搞定了,想要更新并仅显示一张图片而不是整个SD卡。考虑到如果SD卡上有很多内容,重新挂载SD卡可能需要很长时间。是否有一种方法只更新单个项目? - Erik
这段代码已经有些老了,但可能对某些人有所帮助——一个更加具体的路径: sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)))); - user1545072
4
实际上,使用Android 4.4甚至会出现java.lang.SecurityException:Permission Denial: not allowed to send broadcast android.intent.action.MEDIA_MOUNTED 的错误,如果想要尝试这样做。正确的方法是使用MediaScannerConnection.scanFile。请参见其他答案中的示例。 - Holger
1
不再这样做的原因有:1. 几乎在所有当前设备上都无法工作。2. Api < 8现在不需要支持。3. 仅为了编码方便而产生巨大浪费 - Meow Cat 2012
弃用的方法 - Thorny84
显示剩余3条评论

30

或者您可以使用以下方法:

private void scanFile(String path) {

        MediaScannerConnection.scanFile(MainActivity.this,
                new String[] { path }, null,
                new MediaScannerConnection.OnScanCompletedListener() {

                    public void onScanCompleted(String path, Uri uri) {
                        Log.i("TAG", "Finished scanning " + path);
                    }
                });
    }

调用文件扫描功能方式如下:
scanFile(yourFile.getAbsolutePath());

1
非常不错,简单易实现,对我在4.4上运行良好。 - gprathour
1
在4.4.4版本中无法工作...甚至没有任何错误!在清单文件中是否需要某些权限? - Mayur R. Amipara
在4.4.2上运行良好。 - Logic1
目前使用的是4.4.2版本,但它无法正常工作(单个文件,简单情况)。有人知道为什么这种方法的行为如此不稳定,似乎只在一半的情况下起作用吗? - JM Lord
2
Uri 不为空并显示路径,但在 Android 7.1 模拟器中无法在图库中显示图像。 - dakshbhatt21
显示剩余2条评论

11

如果你只想在相册中显示一张图片,请不要执行sendBroadcast操作。那会是一种很浪费资源的做法。你需要创建一个MediaScannerConnectionClient对象,然后通过它创建一个MediaScannerConnection对象并调用connect()方法去扫描文件。

以下是示例:

private MediaScannerConnectionClient mediaScannerConnectionClient = 
    new MediaScannerConnectionClient() {

    @Override
    public void onMediaScannerConnected() {
        mediaScannerConnection.scanFile("pathToImage/someImage.jpg", null);
    }

    @Override
    public void onScanCompleted(String path, Uri uri) {
        if(path.equals("pathToImage/someImage.jpg"))
            mediaScannerConnection.disconnect();
    }
};
new MediaScannerConnection(context, mediaScannerConnectionClient).connect();

3
什么是MEDIA_SCANNER_CONNECTION? - atreat

5
让您的活动实现'MediaScannerConnectionClient',并将其添加到您的活动中:
private void startScan() 
{ 
    if(conn!=null) conn.disconnect();  
    conn = new MediaScannerConnection(YourActivity.this,YourActivity.this); 
    conn.connect(); 
} 

@Override 
public void onMediaScannerConnected() { 
    try{
        conn.scanFile(yourImagePath, "image/*");
       } catch (java.lang.IllegalStateException e){
       }
}

@Override 
public void onScanCompleted(String path, Uri uri) { 
    conn.disconnect(); 
} 

0

使用Intent代替MediaScannerConnectionMediaScannerConnection会导致您的应用程序出现IMediaScannerListener.Stub mListener的gc错误。

Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri fileContentUri = Uri.parseFile(permFile); // With 'permFile' being the File object
mediaScannerIntent.setData(fileContentUri);
sendBroadcast(mediaScannerIntent);

0
File file = new File(absolutePath);
Uri uri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
sendBroadcast(intent);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接