微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

您如何从DocumentsContract.Document获取MediaStore元数据?

如何解决您如何从DocumentsContract.Document获取MediaStore元数据?

我的目标是能够使用Intent.ACTION_OPEN_DOCUMENT_TREE获取用户选择的目录,然后从该目录获取所有音频文件及其元数据。我已经可以使用Intent.ACTION_OPEN_DOCUMENT_TREE获取用户选择的目录,但是我无法提取音频文件元数据。我得到的是null而不是元数据。我认为问题在于返回到onActivityResult的{​​{1}}的Uri与MediaStore Uri不兼容。

我目前可以使用以下代码从MediaStore获取元数据:

Intent

在这里查询 void getAudioFiles(){ String[] projection = new String[]{ MediaStore.Audio.Media._ID,MediaStore.Audio.Media.disPLAY_NAME,MediaStore.Audio.Media.IS_MUSIC,MediaStore.Audio.Media.ARTIST,MediaStore.Audio.Media.TITLE,MediaStore.Images.Media.DATA }; String selection = MediaStore.Audio.Media.IS_MUSIC + " != ?"; String[] selectionArgs = new String[]{"0"}; String sortOrder = MediaStore.Video.Media.TITLE + " ASC"; try (Cursor cursor = getApplicationContext().getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,projection,selection,selectionArgs,sortOrder)) { if (cursor != null) { List<Uri> newURIs = getURIs(cursor); } } } private List<Uri> getURIs(Cursor cursor) { ArrayList<Uri> newURIs = new ArrayList<>(); int idCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID); int nameCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.disPLAY_NAME); int titleCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE); int artistCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST); int dataCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA); while (cursor.movetoNext()) { long id = cursor.getLong(idCol); String displayName = cursor.getString(nameCol); String title = cursor.getString(titleCol); String artist = cursor.getString(artistCol); String data = cursor.getString(dataCol); Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,id); if (!uriMap.containsKey(uri)) { AudioURI audioURI = new AudioURI(uri,data,displayName,artist,title,id); uriMap.put(uri,audioURI); } newURIs.add(uri); } return newURIs; } 。这使我相信,我需要一种基于MediaStore.Audio.Media.EXTERNAL_CONTENT_URI的{​​{1}}

返回的Uri从MediaStore中进行选择的方法

这是我第一次尝试使用用户选择的目录获取元数据。

首先,我设置一个onClickListener来要求用户选择目录:

onActivityResult

然后我得到结果并尝试解析数据:

Intent

这对于查找文件而不是获取元数据非常有用。每个 @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); String title = getResources().getString(R.string.pick_folder); Intent chooser = Intent.createChooser(intent,title); if (intent.resolveActivity(activityMain.getPackageManager()) != null) { startActivityForResult(chooser,REQUEST_CODE_OPEN_FOLDER); } } 列都有一个空值。

对于我的第二次尝试,我尝试使用 @Override public void onActivityResult(int requestCode,int resultCode,Intent resultData) { if (requestCode == REQUEST_CODE_OPEN_FOLDER && resultCode == Activity.RESULT_OK) { Uri uri = null; if (resultData != null) { uri = resultData.getData(); final int takeFlags = resultData.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION); ContentResolver contentResolver = activityMain.getContentResolver(); contentResolver.takePersistableuriPermission(uri,takeFlags); traverseDirectoryEntries(uri); } } } void traverseDirectoryEntries(Uri rootUri) { Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree( rootUri,DocumentsContract.getTreeDocumentId(rootUri)); getFiles(childrenUri,rootUri); } private void getFiles(Uri childrenUri,Uri rootUri) { ContentResolver contentResolver = activityMain.getContentResolver(); List<TreeViewNode> treeViewNodes = new LinkedList<>(); String selection = MediaStore.Audio.Media.IS_MUSIC + " != ? OR" + DocumentsContract.Document.COLUMN_MIME_TYPE + " == ?"; String[] selectionArgs = new String[]{"0"},DocumentsContract.Document.MIME_TYPE_DIR}; try (Cursor cursor = contentResolver.query(childrenUri,new String[]{ DocumentsContract.Document.COLUMN_DOCUMENT_ID,DocumentsContract.Document.COLUMN_disPLAY_NAME,DocumentsContract.Document.COLUMN_MIME_TYPE,MediaStore.Audio.Media._ID,MediaStore.Audio.Media.DATA},null)) { if (cursor != null) { int idCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID); int nameCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.disPLAY_NAME); int titleCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE); int artistCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST); int dataCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA); while (cursor.movetoNext()) { String docId = cursor.getString(0); String name = cursor.getString(1); String mime = cursor.getString(2); long id = cursor.getLong(idCol); this.uriID = id; String displayName = cursor.getString(nameCol); String title = cursor.getString(titleCol); String artist = cursor.getString(artistCol); String data = cursor.getString(dataCol); Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,id); if (isDirectory(mime)) { Uri newNode = DocumentsContract.buildChildDocumentsUriUsingTree( rootUri,docId); getFiles(newNode,rootUri); } else { audioFiles.add(childrenUri); } } } } } private static boolean isDirectory(String mimeType) { return DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType); } ,但收到“ java.lang.RuntimeException:setDataSource失败:status = 0x80000000”:

MediaStore.Audio.Media

我认为这可能是一个安全问题,因为MediaMetadataRetriever没有具有读取权限的根uri。这是因为从MediaStore Uri检索的相同文件与MediaMetadataRetriever兼容。

对于我的第三次尝试,我尝试根据MediaMetadataRetriever的{​​{1}}返回的文档ID从MediaStore中进行选择,但是我得到了“ android.database.sqlite.sqliteException:没有这样的列:document_id(代码1 sqlITE_ERROR)”:

        MediaMetadataRetriever mediaMetadataRetriever;
        mediaMetadataRetriever = new MediaMetadataRetriever();
        mediaMetadataRetriever.setDataSource(activityMain.getApplicationContext(),childrenUri);

应该如何从用户选择的目录中获取音频文件元数据?

解决方法

Intent.ACTION_OPEN_DOCUMENT_TREE为您提供了不同于媒体存储库的其他提供商的SAF uri。

用saf uri查询媒体存储毫无意义。

在最新的Android上,您可以将一些安全的uri转换为mediastore的uri。反之亦然。

然后使用媒体存储库urie查询媒体存储库。

,

我找到了解决此问题的一种方法:

    private void getAudioUri(String displayName) {
        ContentResolver contentResolver = activityMain.getContentResolver();
        String selection =  MediaStore.Audio.Media.DISPLAY_NAME + " == ?";
        String[] selectionArgs = new String[]{displayName};
        try (Cursor cursor = contentResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,new String[]{
                        MediaStore.Audio.Media._ID,MediaStore.Audio.Media.DISPLAY_NAME,MediaStore.Audio.Media.TITLE,MediaStore.Audio.Media.ARTIST,MediaStore.Audio.Media.DATA
                },selection,selectionArgs,null)) {
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    int idCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID);
                    int nameCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME);
                    int titleCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
                    int artistCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
                    int dataCol = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
                    long id = cursor.getLong(idCol);
                    this.mediaStoreUriID = id;
                    String displayName2 = cursor.getString(nameCol);
                    String title = cursor.getString(titleCol);
                    String artist = cursor.getString(artistCol);
                    String data = cursor.getString(dataCol);
                    Uri uri1 = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,id);
                }
            }
        }
    }

在这种情况下,传入的displayName来自文档的MediaStore.Audio.Media.DISPLAY_NAME列。出于某种原因,可以从Intent中提取的Uri中获得元数据。

我不确定文件是否始终都具有“ MediaStore.Audio.Media.DISPLAY_NAME”。不过,这适用于Android Pie和Marshmellow。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。