应用程序重置后无法播放音频文件 - java.io.IOException: setDataSource 失败。: status=0x80000000
Unable to play audio file after application reset - java.io.IOException: setDataSource failed.: status=0x80000000
我正在创建允许向用户播放音频文件、创建多个播放列表和交叉淡入淡出每个 song/playlist 等的应用程序。
到目前为止一切正常,我可以选择歌曲文件,并通过将它们加载到 MediaPlayer 中来正确播放它们
问题是如果我重新启动应用程序。神奇的是,以前正确读取的所有 Uri 都不再可以访问了?
这是我加载歌曲的方式(删除了一些部分 - 视图等)
val intent = new Intent()
.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
.setAction(Intent.ACTION_OPEN_DOCUMENT )
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
startActivityForResult.launch(intent);
private final ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
val data = result.getData();
if (data.getData() != null) {
val uri = data.getData();
songOutOfUri(uri);
} else if (data.getClipData() != null && data.getClipData().getItemCount() > 0) {
val clipData = data.getClipData();
for (int i = 0; i < clipData.getItemCount(); i++) {
val uri = clipData.getItemAt(i).getUri();
songOutOfUri(uri);
}
}
///...view update
}
}
);
private void songOutOfUri(Uri uri) {
val file = new File(uri.getPath());
val song = Song.builder()
.filename(file.getName())
.fileUri(uri.toString())
.filePath(file.getPath())
.build();
song.save();
playlistService.addSongToPlaylist(playlist, song);
}
基本上这个意图的结果是一些歌曲被添加到我的播放列表中,它们包含文件名(为了更好地显示)文件路径和 fileUri。使用 https://github.com/ImangazalievM/ReActiveAndroid(因此 uri 到字符串)
将所有内容保存到数据库中
然后我尝试播放文件 :
///...
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(currentSong.getFileUri()));
mediaPlayer.prepare();
mediaPlayer.seekTo(position);
mediaPlayer.start();
它适用于多首歌曲,但只有在我终止/重置应用程序之前
如果我再次重新打开应用程序,我会收到媒体播放器错误:
W/System.err: java.io.IOException: setDataSource failed.: status=0x80000000
W/System.err: at android.media.MediaPlayer.nativeSetDataSource(Native Method)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1243)
W/System.err: at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1230)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1147)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1072)
示例持久歌曲:
{
"id":20,
"filename":"05 Mindi Abair - Lucy's.mp3",
"fileUri":"content://com.android.externalstorage.documents/document/primary%3AMusic%2Fsongs%2F05%20Mindi%20Abair%20-%20Lucy's.mp3",
"filePath":"/document/primary:Music/songs/05 Mindi Abair - Lucy's.mp3",
"currentPosition":0
}
也试图读取文件并使用 fileDescriptor 播放,但即使在第一次尝试时也得到了 FileNotFound(没有重置)
尝试在使用 uri 重置之前播放它,但没有文件描述符
File file = new File(currentSong.getFilePath()); //also tried with Uri.parse(song.getFileUri)
FileInputStream is = new FileInputStream(file);
mediaPlayer.setDataSource(is.getFD());
//throws java.io.FileNotFoundException: /document/primary:Music/songs/05 Mindi Abair - Lucy's.mp3: open failed: ENOENT (No such file or directory)
Manifest当然有读取存储的权限
我能够通过官方文档中的试验解决问题 https://developer.android.com/training/data-storage/shared/documents-files
然后检查 github
上的一些示例
对于在打开文件时遇到类似问题的任何人
开始选择文件:
Intent intent = new Intent(ACTION_OPEN_DOCUMENT)
.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
.setFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForSelectedFiles.launch(intent);
startActivityForSelectedFiles 保持不变
然后关键的第 1 部分是当我们收到 URI 时,我们必须使用权限正确标记它。
requireActivity()
.getApplicationContext()
.getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
//rest of uri handling
val file = new File(uri.getPath());
val song = Song.builder()...
然后每当我们想使用 uri 访问我们的文件时:
...
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor());
val fileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor());
mediaPlayer.prepare();
mediaPlayer.seekTo(position);
mediaPlayer.start();
现在每次都有效
我正在创建允许向用户播放音频文件、创建多个播放列表和交叉淡入淡出每个 song/playlist 等的应用程序。
到目前为止一切正常,我可以选择歌曲文件,并通过将它们加载到 MediaPlayer 中来正确播放它们
问题是如果我重新启动应用程序。神奇的是,以前正确读取的所有 Uri 都不再可以访问了?
这是我加载歌曲的方式(删除了一些部分 - 视图等)
val intent = new Intent()
.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
.setAction(Intent.ACTION_OPEN_DOCUMENT )
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
startActivityForResult.launch(intent);
private final ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
val data = result.getData();
if (data.getData() != null) {
val uri = data.getData();
songOutOfUri(uri);
} else if (data.getClipData() != null && data.getClipData().getItemCount() > 0) {
val clipData = data.getClipData();
for (int i = 0; i < clipData.getItemCount(); i++) {
val uri = clipData.getItemAt(i).getUri();
songOutOfUri(uri);
}
}
///...view update
}
}
);
private void songOutOfUri(Uri uri) {
val file = new File(uri.getPath());
val song = Song.builder()
.filename(file.getName())
.fileUri(uri.toString())
.filePath(file.getPath())
.build();
song.save();
playlistService.addSongToPlaylist(playlist, song);
}
基本上这个意图的结果是一些歌曲被添加到我的播放列表中,它们包含文件名(为了更好地显示)文件路径和 fileUri。使用 https://github.com/ImangazalievM/ReActiveAndroid(因此 uri 到字符串)
将所有内容保存到数据库中然后我尝试播放文件 :
///...
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(getApplicationContext(), Uri.parse(currentSong.getFileUri()));
mediaPlayer.prepare();
mediaPlayer.seekTo(position);
mediaPlayer.start();
它适用于多首歌曲,但只有在我终止/重置应用程序之前 如果我再次重新打开应用程序,我会收到媒体播放器错误:
W/System.err: java.io.IOException: setDataSource failed.: status=0x80000000
W/System.err: at android.media.MediaPlayer.nativeSetDataSource(Native Method)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1243)
W/System.err: at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1230)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1147)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1072)
示例持久歌曲:
{
"id":20,
"filename":"05 Mindi Abair - Lucy's.mp3",
"fileUri":"content://com.android.externalstorage.documents/document/primary%3AMusic%2Fsongs%2F05%20Mindi%20Abair%20-%20Lucy's.mp3",
"filePath":"/document/primary:Music/songs/05 Mindi Abair - Lucy's.mp3",
"currentPosition":0
}
也试图读取文件并使用 fileDescriptor 播放,但即使在第一次尝试时也得到了 FileNotFound(没有重置)
尝试在使用 uri 重置之前播放它,但没有文件描述符
File file = new File(currentSong.getFilePath()); //also tried with Uri.parse(song.getFileUri)
FileInputStream is = new FileInputStream(file);
mediaPlayer.setDataSource(is.getFD());
//throws java.io.FileNotFoundException: /document/primary:Music/songs/05 Mindi Abair - Lucy's.mp3: open failed: ENOENT (No such file or directory)
Manifest当然有读取存储的权限
我能够通过官方文档中的试验解决问题 https://developer.android.com/training/data-storage/shared/documents-files 然后检查 github
上的一些示例对于在打开文件时遇到类似问题的任何人
开始选择文件:
Intent intent = new Intent(ACTION_OPEN_DOCUMENT)
.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
.setFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForSelectedFiles.launch(intent);
startActivityForSelectedFiles 保持不变
然后关键的第 1 部分是当我们收到 URI 时,我们必须使用权限正确标记它。
requireActivity()
.getApplicationContext()
.getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
//rest of uri handling
val file = new File(uri.getPath());
val song = Song.builder()...
然后每当我们想使用 uri 访问我们的文件时:
...
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor());
val fileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor());
mediaPlayer.prepare();
mediaPlayer.seekTo(position);
mediaPlayer.start();
现在每次都有效