将 Uri 发送到 MediaMetadataRetriever 中的 setDataSource() 时出现 IllegalArgumentException

IllegalArgumentException when sending Uri to setDataSource() in MediaMetadataRetriever

我遇到过类似的问题:-

MediaMetadataRetriever setdatasource IllegalArgumentException

IllegalArgumentException in setDataSource for MediaPlayer

MediaMetadataRetriever setDataSource throws IllegalArgumentException

所有建议我添加外部存储权限或该路径可能错误或 invalid.The setDataSource() 方法可以同时使用 ContextUri 。当我发送它们时我获取 IllegalArgumentException .

这是我发送到 Uri 的方法:-

static List<String> getMusicNames(Context context,List<Uri> Uris){//get the music names


List<String> musicNames=new ArrayList<String>();


for(Uri uri:Uris){
    MediaMetadataRetriever mData = new MediaMetadataRetriever();
    mData.setDataSource(context, uri);//<<<<<at this line the error
    musicNames.add(mData.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE));


}//returning the music names
return musicNames;

}

我这样发送 Uri :-

Arrays.asList(songUri)

可以是多个也可以只有一个Uri。

当我调试这个方法的 Uri 时:-content://com.android.externalstorage.documents/document/primary%3ADownload%2F01-1085088-Full%20Song-Track%201%20_%20Sakkarathil%20amma.mp3

我确定音频文件在那里,我在另一个应用程序中打开了它。

我从 sharedpreferences 中获取 Uri 是这样的:-

Uri.parse(pref.getString("gotsong",""))//get the song Uri

我在 sharedpreferences 中这样设置 Uri :-

editor.putString("gotsong", uri.toString());// save the song uri

其实如果我不是从共享首选项中检索而是直接从文件中获取,也不例外。

根据神谕 IllegalArgumentException

public class IllegalArgumentException extends RuntimeException Thrown to indicate that a method has been passed an illegal or inappropriate argument.

这是原来的 setDataSource() method.I 指出异常抛出的地方 :-

public void setDataSource(Context context, Uri uri)
    throws IllegalArgumentException, SecurityException {
    if (uri == null) {
        throw new IllegalArgumentException()//<<<<<<<<<<<<<<<<<<<<<<<<<<<HERE
    }

    String scheme = uri.getScheme();
    if(scheme == null || scheme.equals("file")) {
        setDataSource(uri.getPath());
        return;
    }

    AssetFileDescriptor fd = null;
    try {
        ContentResolver resolver = context.getContentResolver();
        try {
            fd = resolver.openAssetFileDescriptor(uri, "r");
        } catch(FileNotFoundException e) {
            throw new IllegalArgumentException();//<<<<<<<<<<<<<<<<<<<<<<<<<<<HERE
        }
        if (fd == null) {
            throw new IllegalArgumentException();//<<<<<<<<<<<<<<<<<<<<<<<<<<<HERE
        }
        FileDescriptor descriptor = fd.getFileDescriptor();
        if (!descriptor.valid()) {
            throw new IllegalArgumentException();//<<<<<<<<<<<<<<<<<<<<<HERE
        }
        // Note: using getDeclaredLength so that our behavior is the same
        // as previous versions when the content provider is returning
        // a full file.
        if (fd.getDeclaredLength() < 0) {
            setDataSource(descriptor);
        } else {
            setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
        }
        return;
    } catch (SecurityException ex) {
    } finally {
        try {
            if (fd != null) {
                fd.close();
            }
        } catch(IOException ioEx) {
        }
    }
    setDataSource(uri.toString());
}

显然 Uri 不为空,所以它是其他 3 个原因之一,其中一个在 FileNotFoundException 中,另外两个我不明白。

我的问题其实和这个问题类似:-Save uri to sharedPreferences and play with mediaplayer

我发现问题是如果 Uri 被保存在 Sharedpreferences 中而没有读取和写入 Uri 的权限,特别是 Uri Iam 针对音频文件之类的文件,那么该方法适用于例如我发送文件Uri 直接,如果我保存在共享 pref 中包含文件的文件夹路径,然后提取 Uris 并将它们发送到该方法,或者如果我授予这些权限以在共享 pref 中保存 file 然后检索并发送到方法。

所以我实现了 Recek 的回答:-

首先我的意图是ACTION_OPEN_DOCUMENT:-

     intent.setType("audio/*");
                intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
                intent.addCategory(Intent.CATEGORY_OPENABLE);

我在第一次得到意图后添加这部分的地方:-

     this.grantUriPermission(this.getPackageName(), data.getData(), Intent.FLAG_GRANT_READ_URI_PERMISSION);
        final int takeFlags = data.getFlags()
                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);            // Check for the freshest data.
        //noinspection WrongConstant
        this.getContentResolver().takePersistableUriPermission(data.getData(), takeFlags);

-保存到共享首选项。并检索 normally.Whats 有趣的是,直接来自文件的 Uri 如下所示:-content://com.android.externalstorage.documents/document/primary%3ADownload%2FDeath%20Grips%20-%20Get%20Got.mp3

如果未保存在共享首选项中,则获取结果。

然而,从新 Intent 中得到的结果看起来是这样的:- content://com.android.providers.downloads.documents/document/433

能救的那个

编辑

也可以在没有读取 Uri 权限的情况下保存和检索文件夹树 Uri,只有文件树需要 Uri permission.I 试图从 Uri 树获取文件夹树但是这在获取文件时不起作用,the Uri 必须来自 Intent。

与你的路径中的utf8字符串有关。 所以在使用它之前,你需要从 Utf8 中解码 url。那肯定有用。

URLDecoder.decode(video, "UTF-8")