我正在实现一个游戏,我想使用一个且只有一个 MediaPlayer 实例,它在与 UI 不同的线程中运行。每个音频文件都被发送到一个 FIFO 队列,如果没有文件正在播放,或者队列中的前一个文件播放完,就会立即播放。我已经实现了一个单例类来支持这一点,如下所示:
public class ThePlayer {
private static ThePlayer instance = null;
private Context context;
Thread playerThread;
BlockingQueue<Integer> listIDs = new LinkedBlockingQueue<Integer>();
MediaPlayer player;
Integer playID;
private ThePlayer() {
player = null;
playerThread = new Thread(new Runnable() {
//Object locker = new Object();
public void run() {
while (true) {
try {
playID = listIDs.take(); // blocks if list empty
Log.d(this.getClass().getName(), "Took ID 0x" + Integer.toHexString(playID));
player = MediaPlayer.create(context, playID);
player.setOnCompletionListener(
new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
mp = null;
synchronized (playerThread) {
Log.d(this.getClass().getName(), "Finished playing 0x"+Integer.toHexString(playID));
playerThread.interrupt();
}
}
});
player.start();
Log.d(this.getClass().getName(), "Started playing 0x"+Integer.toHexString(playID));
synchronized (this) {
Log.d(this.getClass().getName(), "Now wait to finish");
wait(); // until finished playing
}
} catch (InterruptedException ie) {
Log.d(getClass().getName(), "Player thread wait interrupted");
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
playerThread.setName("PlayerThread");
playerThread.start();
}
public static ThePlayer getInstance()
{
if(instance == null)
{
instance = new ThePlayer();
}
return instance;
}
public void play(Context _ctx, int id) {
context = _ctx;
listIDs.add(id);
Log.d(this.getClass().getName(), "Added ID 0x" + Integer.toHexString(id));
}
public void stop() {
//TODO: implement
}
}
一般来说,这很好用,但一个特定的文件无法以不一致的方式播放。换句话说,在大多数情况下,它不播放,但偶尔会播放。所有日志条目都表明文件已排队,MediaPlayer 已分配并启动,并且 onCompletion 函数已被调用。绝不会抛出异常。这发生在摩托罗拉 Defy+ 手机和各种模拟器配置上。它不会发生在我的三星 Galaxy Tab II 10.1 上,我猜测这是功能更强大的硬件的功能,或者可能是更高级的 Android 版本。