MediaPlayer setDataSource需要最佳实践建议。

7

阅读了 "媒体播放" 和 "MediaPlayer" Android 文档后,我仍然感到困惑,需要有经验的建议关于 setDataSource 这个重载方法。

我正在我的项目中的Service组件中使用MediaPlayer来播放音乐,这个服务将成为前台服务。我将音乐文件(.mp3)放在apk的res/raw文件夹中。 要开始播放,我知道我必须准备好MediaPlayer对象。由于Android应用程序中的服务默认使用单个进程和主线程,因此我不希望用户在MediaPlayer准备自己时遇到ANR(如果raw文件夹中的媒体文件很大,则会出现此问题)。 然后我使用prepareAsync而不是prepare(同步)。所以我不能使用:
mp = MediaPlayer.create(context, R.raw.myfile);

因为这已经在内部调用了prepare()但没有调用prepareAsync()。所以基本上我有两个选项(四个中的两个):
Uri myUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.myfile);
mp.setDataSource(context, myUri);

或者

AssetFileDescriptor afd = context.getResources().openRawResourceFd(R.raw.myfile);
mp.setDataSource(fd.getFileDescriptor());
afd.close();

使用其中之一后,我可以简单地使用:
mp.prepareAsync();

最后我的问题是,“包括这些不同的方法,哪一个是最好的选择?它们之间有什么优劣势吗?我有遗漏了什么吗?”


就我个人而言,我喜欢最后一种方法,因为它在代码中不使用字符串。虽然我不知道这是否算作很大的“优点”。 - Geobits
@Geobits,避免在代码中使用常量字符串是一个好的实践,我知道。但是FileDescriptor是Android对本地文件的首选。谢谢你的评论。我建议你阅读我对被接受答案的评论。 - Fredrick Gauss
1个回答

9
调用createsetDataSource的不同方式没有任何实际好处。静态的create方法几乎只是调用setDataSourceprepare。各种setDataSource方法在内部相互调用,最终归结为两个可能的本地调用,一个使用描述远程URI的字符串,另一个使用本地文件描述符。自己创建文件描述符可能会略微提高性能,但在实际情况下不会有明显的影响。
对于本地文件播放,就像你在代码中展示的那样,简单地调用prepare(或静态的create方法)并不是一种坏的做法。底层播放器应该没有问题确定相关的元数据并快速返回,无论文件大小如何。而prepareAsync方法更适用于网络流,因为许多情况可能会导致一些意外的延迟。如果您正在设计一个通用的播放器,那么使用prepareAsync方法是正确的选择,但如果您只是播放原始资源,则不会有任何区别。提供各种方法只是为了方便(请注意create的javadoc)。

阅读了您的回答后,我查看了Android框架,并理解了您所说的内容。我看到了private native void _setDataSource方法,并注意到setDataSource(FileDescriptor fd, long offset, long length)方法更适用于本地访问。我大致推断出FileDescriptor用于本地,而Uri用于远程(流)目的。 - Fredrick Gauss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接