android - 如何让 WakefulService (IntentService) 等到 MediaPlayer 完成?

标签 android media-player intentservice

我正在尝试制作一个应用程序,它在预定的时间使用 MediaPlayer 播放一系列声音。为了正确处理唤醒锁并安排播放,我使用了 CommonsWare's WakefulIntentService .

不幸的是,IntentService 的工作线程在我调用 MediaPlayer.play() 后立即退出,并且 MediaPlayer 注册的监听器都没有被调用。相反,会记录异常:

W/MessageQueue(6727): Handler (android.media.MediaPlayer$EventHandler) {4160d820} sending message to a Handler on a dead thread
W/MessageQueue(6727): java.lang.RuntimeException: Handler (android.media.MediaPlayer$EventHandler) {4160d820} sending message to a Handler on a dead thread
W/MessageQueue(6727):   at android.os.MessageQueue.enqueueMessage(MessageQueue.java:294)
W/MessageQueue(6727):   at android.os.Handler.sendMessageAtTime(Handler.java:473)
W/MessageQueue(6727):   at android.os.Handler.sendMessageDelayed(Handler.java:446)
W/MessageQueue(6727):   at android.os.Handler.sendMessage(Handler.java:383)
W/MessageQueue(6727):   at android.media.MediaPlayer.postEventFromNative(MediaPlayer.java:2063)
W/MessageQueue(6727):   at dalvik.system.NativeStart.run(Native Method)

据我了解,这是由于 MediaPlayer 完成时工作线程已经死掉造成的。如果我通过调试器暂停线程并让播放器完成,一切正常。

在我的监听器中,我不仅释放了 MediaPlayer 的资源,而且还使用 OnCompletionListener 进行连续的 MediaPlayer.play() 调用,直到声音队列为空。

我尝试在初始 play() 调用之后立即放置一个等待循环,检查自定义完成标志,但它似乎卡住了,因为 MediaPlayer 的回调是在同一线程 play 上调用的() 被调用。

问题是,如何让工作线程在我让它退出之前不退出(即已经处理完并且最后一次调用onCompletion()方法?

这是我的服务代码:

public class SoundService extends WakefulIntentService {
    private static final TAG = "SoundService";
    private final Queue<SoundDescriptor> soundQueue = new ConcurrentLinkedQueue<SoundDescriptor>();

    private final OnCompletionListener onComediaPlayerletionListener = new OnComediaPlayerletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            mediaPlayer.reset();
            try {
                if (!playNextFromQueue(mediaPlayer)) {
                    Log.v(TAG, "Reached end of queue. Cleaning up.");
                    release();
                }
            } catch (Exception e) {
                Log.e(TAG, "Exception!", e)
                release();
            }
        }
    };
    private final OnErrorListener onErrorListener = new OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
            Log.v(TAG, "Error!!");
            release();
            return false;
        }
    };

    public SoundService() {
        // populate soundQueue
    }

    protected void doWakefulWork(Intent intent) {
        MediaPlayer mediaPlayer = new MediaPlayer();
        mediaPlayer.setOnComediaPlayerletionListener(onComediaPlayerletionListener);
        mediaPlayer.setOnErrorListener(onErrorListener);
        playNextFromQueue(mediaPlayer);
    }

    private boolean playNextFromQueue(MediaPlayer mediaPlayer) throws IllegalArgumentException, IllegalStateException, IOException {
        SoundDescriptor descriptor = soundQueue.poll();
        if (descriptor != null) {
            mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
            descriptor.close();
            mediaPlayer.prepare();
            mediaPlayer.start();
            return true;
        } else {
            return false;
        }
    }
}

最佳答案

To properly handle the wake lock and schedule the playback I used CommonsWare's WakefulIntentService.

这不是一个合适的选择。

Unfortunately, the IntentService's worker thread quits right after I call MediaPlayer.play() and neither MediaPlayer registered listeners are called.

这就是为什么它不是一个合适的选择。 :-)

The question is, how can I make the worker thread not quit before I let it do so (i.e. the has been processed and the onCompletion() method has been called for the last time?

不要使用 WakefulIntentService。不要使用 IntentService。使用服务。自己管理WakeLock,当音频结束时在服务上调用stopSelf()

关于android - 如何让 WakefulService (IntentService) 等到 MediaPlayer 完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14085857/

相关文章:

java - 添加 GCM 后端时 Android 应用构建失败

java - 在android中实现Socket.io的最佳方式

ios - 如何在 iPhone 中播放 Youtube 视频

android - 播放短 .wav 文件 - Android

android - 从 intentservcie 回调到 jobservice

android - 权限拒绝 : this requires android. 权限。INTERACT_ACROSS_USERS_FULL

android - Android 中的 GPS 区域

android - Media Player 突然停止并在 logcat : TimedEventQueue(33): Event 4 was not found in the queue, 中显示警告已取消?

android - IntentService 的 StartForeground

java - 将 Parcelable 与带有 Hashmap 的对象一起使用