替代解决方案 #1:使用 Resources.getIdentifier()
为什么不使用 getResources().getIdentifier() 来获取资源的 id 并像往常一样使用静态 MediaPlayer.create() ?
public int getIdentifier (String name, String defType, String defPackage)
获取标识符() http://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String,%20java.lang.String,%20java.lang.String)获取您的资源名称 (test0)、资源类型(raw)、您的包名称并返回实际的资源 ID。
MediaPlayer mp;
//String filename = "android.resource://" + this.getPackageName() + "/raw/test0";
mp=MediaPlayer.create(getApplicationContext(), getResources().getIdentifier("test0","raw",getPackageName()));
mp.start();
我已经测试了这段代码并且它有效。
Update #1:
替代解决方案#2:使用 Uri.parse()
我也测试了这段代码并且它也有效。将您的资源路径作为 URI 传递给 setDataSource()。我刚刚对您的代码进行了更改以使其正常工作。
String filename = "android.resource://" + this.getPackageName() + "/raw/test0";
mp = new MediaPlayer();
try { mp.setDataSource(this,Uri.parse(filename)); } catch (Exception e) {}
try { mp.prepare(); } catch (Exception e) {}
mp.start();
Update #2: Answer is NO
关于 setDataSource(String) 调用
看到您的评论后,看来您确实希望将 setDataSource(string) 用于您的目的。我不明白为什么。但是,我认为,出于某种原因,您试图避免使用“上下文”。如果情况并非如此,那么上述两个解决方案应该非常适合您,或者如果您试图避免上下文,恐怕使用签名 setDataSource(String) 调用的函数是不可能的。原因如下,
MediaPlayer setDataSource() 函数具有以下选项,您只对 setDataSource(String) 感兴趣,
setDataSource(String) 内部调用 setDataSource(String path, String[]keys, String[]values) 函数。如果你可以检查它source https://github.com/android/platform_frameworks_base/blob/master/media/java/android/media/MediaPlayer.java,
public void setDataSource(String path)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(path, null, null);
}
如果您检查 setDataSource(String path, String[]keys, String[]values) 代码,您将看到以下条件根据其方案过滤路径,特别是如果它是“文件”方案,它会调用 setDataSource(FileDescriptor) 或如果方案不是“文件”,则调用本机 JNI 媒体函数。
{
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
// handle non-file sources
nativeSetDataSource(
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
path,
keys,
values);
return;
}
final File file = new File(path);
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
setDataSource(fd);
is.close();
} else {
throw new IOException("setDataSource failed.");
}
}
在上面的代码中,您的资源文件 URI 方案将不为 null (android.resource://) 并且setDataSource(String) 将尝试使用本机 JNI 函数 nativeSetDataSource() ,认为您的路径是 http/https/rtsp ,显然该调用也会失败而不会引发任何异常。这就是为什么您对 setDataSource(String) 的调用会毫无异常地转义,并且会在出现以下异常的情况下调用prepare() 。
Prepare failed.: status=0x1
因此 setDataSource(String) 重写无法处理您的资源文件。您需要为此选择另一个覆盖。
另一方面,检查 setDataSource(Context context, Uri uri, Map headers) 使用的 setDataSource(Context context, Uri uri),它使用上下文中的 AssetFileDescriptor、ContentResolver 和 openAssetFileDescriptor 打开 URI,该 URI 成功作为 openAssetFileDescriptor( )可以打开您的资源文件,最后生成的 fd 用于调用 setDataSource(FileDescriptor) 覆盖。
AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
fd = resolver.openAssetFileDescriptor(uri, "r");
// :
// :
// :
if (fd.getDeclaredLength() < 0) {
setDataSource(fd.getFileDescriptor());
} else {
setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
}
总之,您不能按原样使用 setDataSource(String) 覆盖来使用资源 mp3 文件。相反,如果您想使用字符串来播放资源文件,您可以使用上面给出的 MediaPlayer.create() 静态函数和 getIdentifier() 或 Update#1 中给出的 setDataSource(context,uri) 。
请参阅此处的完整源代码以进行更深入的理解:Android 媒体播放器 https://github.com/android/platform_frameworks_base/blob/master/media/java/android/media/MediaPlayer.java
Update #3:
openFrameworks setDataSource(String):
正如我在下面的评论中提到的,openFrameworks 使用 android MediaPlayer 代码 asis。如果您可以参考第4行,
import android.media.MediaPlayer;
线路号:26、27、28 和 218
player = new MediaPlayer(); //26
player.setDataSource(fileName); //27
player.prepare(); //28
private MediaPlayer player; //218
所以,如果你尝试通过android.resource//+ this.getPackageName() + "raw/test0"使用 openFrameworks setDataSource(),您仍然会得到与我在 Update#2 中解释的相同的异常。话虽如此,我只是想试试运气,在谷歌上搜索一下,以双重确定我所说的内容,然后发现了这个openFrameworks 论坛链接 http://forum.openframeworks.cc/t/soundfiles-on-android/6220/9其中之一openFrameworks 核心开发人员 arturo says,
不知道 mediaPlayer 是如何工作的,但所有内容都在 res/raw 中
或 bin/data 被复制到 /sdcard/cc.openframeworks.packagename
根据该评论,您可以尝试在 setDataSource() 中使用复制的路径。无法在 MediaPlayer 的 setDataSource(String) 上使用资源文件,因为它无法接受资源文件路径。请注意,我说的“资源文件路径”以方案开头android.resource//这实际上是一个 jar 位置(在你的 apk 中),而不是物理位置。本地文件将与以方案开头的 setDataSource(String) 一起使用file://.
为了让您清楚地了解要对资源文件执行的操作,请尝试执行下面的代码并在 logcat 中查看结果,
try{
Log.d("RESURI", this.getClass().getClassLoader().getResource("res/raw/test0").toURI().toString());
}
catch(Exception e) {
}
你会得到如下结果:
jar:file:/data/app/<packagename>/<apkname>.apk!/res/raw/test0
这是为了向您表明您尝试访问的资源文件实际上并不是物理路径中的文件,而是您无法使用 setDataSource(String) 方法访问的 jar 位置(在 apk 内)。 (尝试使用 7zip 提取您的 apk 文件,您将在其中看到 res/raw/test0)。
希望有帮助。
PS:我知道它的答案有点冗长,但我希望这能详细解释它。如果可以帮助其他人,请将替代解决方案留在顶部。