Android - MediaStore.Video.query() 返回 null

6

我正在尝试使用方法MediaStore.Video.query()从视频文件中检索元数据(标题、语言、艺术家),但是该方法始终返回null。以下是代码:

String[] columns = {
    MediaStore.Video.VideoColumns._ID,
    MediaStore.Video.VideoColumns.TITLE,
    MediaStore.Video.VideoColumns.ARTIST
};

Cursor cursor = MediaStore.Video.query(getApplicationContext().getContentResolver(), videoUri,columns);

if (cursor != null) {
  cursor.moveToNext();
}

String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE));

有关如何在Android中返回视频元数据的建议?

==更新

在许多地方搜索后,我尝试使用CursorLoader解决方案。然而,从CursorLoader返回的loadInBackground()方法也为空。以下是代码:

String[] columns = {
                MediaStore.Video.VideoColumns.TITLE
        };

        Uri videoUri = Uri.parse("content://mnt/sdcard/Movies/landscapes.mp4");

        CursorLoader loader = new CursorLoader(getBaseContext(), videoUri, columns, null, null, null);

        Cursor cursor = loader.loadInBackground();

        cursor.moveToFirst();

        String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE));

videoUri是什么? MediaStore.Video.Media.EXTERNAL_CONTENT_URI又是什么? - zapl
2个回答

14

Uri.parse("content://media/external/video/media/1234") 是 MediaStore 的 Uri,而不是 Uri.parse("content://mnt/sdcard/Movies/landscapes.mp4")。后者会尝试寻找一个不存在于 mnt 授权下的 ContentProvider

MediaStore 只能处理使用 MediaStore 获取到的 content://media/... 类型的 Uri,不能使用 Uri.parse() 自行构造。

在您的情况下,请使用以下语句来代替:

Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] columns = {
        MediaStore.Video.VideoColumns._ID,
        MediaStore.Video.VideoColumns.TITLE,
        MediaStore.Video.VideoColumns.ARTIST
    };

String selection = MediaStore.Video.VideoColumns.DATA + "=?";
String selectionArgs[] = { "/mnt/sdcard/Movies/landscapes.mp4" };

Cursor cursor = context.getContentResolver().query(uri, columns, selection, selectionArgs, null);
MediaStore.Video.VideoColumns.DATA字段保存视频的路径,您可以通过这种方式搜索特定的视频。至少目前是这样,在未来版本的Android中可能会更改。


您的第二个示例错误地使用了CursorLoader。如果您自己调用loader.loadInBackground(),则会在前台加载数据。请参阅例如http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/

您接下来要做的事情是

    Cursor cursor = getCursor();
    cursor.moveToFirst();
    String title = cursor.getString(/* some index */);

如果你的cursor没有0行且cursor.moveToFirst()失败,那么这将导致CursorIndexOutOfBoundsException异常。游标停留在第一行之前(位置为-1),因此该索引不存在。在您的情况下,这意味着数据库中找不到文件。

为了防止出现这种情况,请使用moveToFirst的返回值 - 只有当存在第一行时它才会是true

    Cursor cursor = getCursor(); // from somewhere
    if (cursor.moveToFirst()) {
        String title = cursor.getString(/* some index */);
    }

一个更完整的示例,包括对null的检查以及在所有情况下关闭游标

    Cursor cursor = getCursor(); // from somewhere
    String title = "not found";
    if (cursor != null) {
        if (cursor.moveToFirst()) {
            title = cursor.getString(/* some index */);
        }
        cursor.close();
    }

我猜你尝试查找的文件要么没有在数据库中索引(重新启动会强制运行索引器),要么路径错误。

或者你使用的路径实际上是一个符号链接,这种情况下MediaStore可能会使用不同的路径。

使用此方法来消除符号链接

    String path  = "/mnt/sdcard/Movies/landscapes.mp4";
    try {
        path = new File(path).getCanonicalPath();
    } catch (IOException e) {
        e.printStackTrace();
    }
是的,我现在测试了一下,它会抛出IndexOutOfBoundsException异常。当我使用cursor.getColumnCount()时,它返回1。
cursor.getColumnCount()返回的是列数,而不是行数。它应该始终与您在“columns”中请求的列数相同。如果您想检查行数,则需要检查cursor.getCount()。
尝试将MediaStore中已知的所有视频转储到logcat中,以防它未按预期显示。
public static void dumpVideos(Context context) {
    Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
    String[] projection = { MediaStore.Video.VideoColumns.DATA };
    Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
    int vidsCount = 0;
    if (c != null) {
        vidsCount = c.getCount();
        while (c.moveToNext()) {
            Log.d("VIDEO", c.getString(0));
        }
        c.close();
    }
    Log.d("VIDEO", "Total count of videos: " + vidsCount);
}

光标返回的不是null。但是,当我调用“cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE))”时,它会抛出NullPointerException。 - Danilo Caetano
@DaniloSantos 如果那行代码抛出了NPE,那么cursornull。你确定它不是一些IndexOutOfBoundsException吗? - zapl
是的,我现在进行了测试,它抛出了“IndexOutOfBoundsException”。当我使用cursor.getColumnCount()时,它返回1 - Danilo Caetano
@DaniloSantos 我猜在MediaStore中没有找到该文件。请查看答案的补充部分。 - zapl
我使用以下代码进行了测试:`File new file = file("文件路径");if(file.isFile){ log.i("ok", "测试通过"); }`测试结果为真。 - Danilo Caetano
@DaniloSantos 并不是所有现有的文件都在MediaStore中,可能因为媒体扫描程序没有识别它(重新启动可以解决),或者它处于根本没有索引的位置(无济于事)。此外,文件可以有不同的路径,但都指向同一个文件(符号链接),如果您的路径版本与MediaStore中的版本不同,您将找不到它。我添加了一段代码,简单地打印所有视频。尝试一下,并检查是否能找到您要寻找的文件。 - zapl

1

我已经更新了你的代码,它可以正常工作,请检查一下

public static void dumpVideos(Context context) {
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
    c.moveToFirst();
    vidsCount = c.getCount();
    do {
        Log.d("VIDEO", c.getString(0));
    }while (c.moveToNext());
    c.close();
}
Log.d("VIDEO", "Total count of videos: " + vidsCount);
}

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