Alternative Solution #1: Using Resources.getIdentifier()
为什么不使用getResources().getIdentifier()来获得资源的ID,并像往常一样使用静态MediaPlayer.create()?
public int getIdentifier (String name, String defType, String defPackage)
getIdentifier()接受你的资源名称(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:
Alternative Solution #2: Using 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
About setDataSource(String) call
看到你的评论后,看起来你正是希望setDataSource(string)能用于你的目的。我不明白为什么。但是,我猜想的是,出于某种原因,你想避免使用 "上下文"。如果不是这样,那么上面的两个解决方案对你来说应该是完美的,如果你想避免使用上下文,恐怕用签名的函数setDataSource(String)调用是不可能的。原因如下。
MediaPlayer setDataSource()函数有以下几个选项,其中你只对setDataSource(String)感兴趣。
setDataSource(String)内部调用setDataSource(String path, String[] keys, String[] values) 函数。如果你能检查其source,
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方案将不会是空的(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,获得成功,因为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()或setDataSource(context,uri),如Update#1中给出的。
请参考完整的源代码,以便在此获得更多理解。安卓媒体播放器
Update #3:
openFrameworks setDataSource(String):
正如我在下面的评论中提到的,openFrameworks使用android MediaPlayer代码。如果你能参考第4行。
import android.media.MediaPlayer;
和线号:26、27、28和218
player = new MediaPlayer(); //26
player.setDataSource(fileName); //27
player.prepare(); //28
private MediaPlayer player; //218
因此,如果你试图通过ardroid.resource//+ this.getPackageName() + "raw/test0"使用openFrameworks来设置DataSource(),你仍然会得到与我在Update#2中解释的相同的异常。说到这里,我试着在谷歌上搜索了一下,以进一步确定我所说的内容,结果发现了以下内容openFrameworks论坛链接 where one of the openFrameworks的核心开发人员Arturo说。
我不知道媒体播放器是如何工作的,但在res/raw
或bin/data中的内容都会被复制到/sdcard/cc.openframeworks.packagename中。
基于这个评论,你可以尝试在setDataSource()中使用复制的路径。在MediaPlayer的setDataSource(String)中使用资源文件是不可能的,因为它不能接受资源文件路径。请注意,我说的 "资源文件路径 "是以方案开头的android.resource//这实际上是一个jar位置(在你的apk内),而不是一个物理位置。本地文件将与setDataSource(String)一起工作,它以方案开始file://.
为了让你清楚地了解你要用资源文件做什么,试着执行下面这段代码,看看logcat中的结果。
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
这是为了告诉你,你试图访问的资源文件实际上不是物理路径上的文件,而是一个jar位置(在apk内),你不能用setDataSource(String)方法访问。(试试用7zip解压你的apk文件,你会看到其中的res/raw/test0)。
希望这有帮助。
PS:我知道这个答案有点长,但我希望这能详细地解释它。如果能帮助别人的话,就把其他的解决方案留在上面。