我需要在Android应用中异步播放声音。
这是一个短暂的哔哔声mp3(1秒长),但我仍然需要它不会阻止当前线程...毫秒很重要,线程正在忙着寻找新的蓝牙数据。
需要播放声音的线程是Intent Service。
我在主线程函数调用开始时附近有以下代码...这是为了准备好MP3,以便以后可以播放。我希望我可以像这样初始化它,然后打电话给某些播放器#PlaySound"我需要的时候。
我的理解是,通过使用OnPreparedListener,MediaPlayer将为我提供在不同线程中播放声音的所有细节。
MediaPlayer objMediaPlayer = MediaPlayer.create(getApplicationContext(),R.raw.beeplow);
objMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
上述似乎有效,没有崩溃。
然后,我想播放声音:
//play sound...
objMediaPlayer.prepareAsync();
这实际上是播放声音......但是,史诗失败了,线程崩溃了。
我做错了什么?
这是LogCat信息,如果这有用的话:
08-19 14:17:51.790 15995-16037/com.example.owner.soundtest V/MediaPlayer﹕ setVideoSurfaceTexture
08-19 14:17:51.790 15995-16037/com.example.owner.soundtest V/MediaPlayer﹕ prepareAsync
08-19 14:17:51.790 15995-16037/com.example.owner.soundtest E/MediaPlayer﹕ prepareAsync called in state 8
08-19 14:17:51.800 15995-16037/com.example.owner.soundtest I/MediaPlayer﹕ Info (973,0)
08-19 14:17:51.800 15995-16037/com.example.owner.soundtest I/MediaPlayer﹕ Don't send intent. msg.arg1 = 0, msg.arg2 = 0
08-19 14:17:51.800 15995-16037/com.example.owner.soundtest V/MediaPlayer-JNI﹕ start
08-19 14:17:51.800 15995-16037/com.example.owner.soundtest V/MediaPlayer﹕ start
08-19 14:17:52.260 15995-16008/com.example.owner.soundtest V/MediaPlayer﹕ message received msg=2, ext1=0, ext2=0
08-19 14:17:52.260 15995-16008/com.example.owner.soundtest V/MediaPlayer﹕ playback complete
08-19 14:17:52.260 15995-16008/com.example.owner.soundtest V/MediaPlayer﹕ callback application
08-19 14:17:52.270 15995-16008/com.example.owner.soundtest W/MessageQueue﹕ Handler (android.media.MediaPlayer$EventHandler) {42fb2890} sending message to a Handler on a dead thread
java.lang.RuntimeException: Handler (android.media.MediaPlayer$EventHandler) {42fb2890} sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:311)
at android.os.Handler.enqueueMessage(Handler.java:623)
at android.os.Handler.sendMessageAtTime(Handler.java:592)
at android.os.Handler.sendMessageDelayed(Handler.java:563)
at android.os.Handler.sendMessage(Handler.java:500)
at android.media.MediaPlayer.postEventFromNative(MediaPlayer.java:2776)
at dalvik.system.NativeStart.run(Native Method)
08-19 14:17:52.270 15995-16008/com.example.owner.soundtest V/MediaPlayer﹕ back from callback
更多信息
是否与" getApplicationContext()"有关?我正在使用...是创建对象的正确方法吗?我仍然是Android的新手,尽管经过了数小时的阅读和研究,所有这些Context和Intent的东西都没有沉淀。
以上所有代码都是在Intent Service的一个线程中调用的......所以它已经完全与UI断开连接。
Hacky Fix
在我的主题开始时这样做:
MediaPlayer objMediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.beeplow);
然后每次我想发出短促的哔哔声时我会这样做:
if(objMediaPlayer.isPlaying()){
objMediaPlayer.stop();
objMediaPlayer.release();
objMediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.beeplow);
}
objMediaPlayer.start();
似乎工作。上帝糟糕的代码和糟糕的形式,但是,是的,我只想播放$ **声音而不花费数小时和数百行代码! Craxy。
正确修复???
以下似乎有效。希望这是正确的方法...当我看到其他解决方案时,它们似乎是50多行代码埋在服务等等。我喜欢下面这个...如果这是正确的如何开除一个线程我将在任何地方这样做!
new Thread(new Runnable() {
@Override
public void run() {
MediaPlayer objMediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.beeplow);
objMediaPlayer.start();
}
}, "PlayBeepLow").start();
答案 0 :(得分:1)
在死线程上向处理程序发送消息
在IntentService
中执行此操作并不安全,因为它在用完工作时会自行停止。
所有上述代码都在Intent Service的一个线程中调用... 所以它已经完全脱离了用户界面。
处理完所有请求后,IntentService-onHandleIntent
会自行停止。
我建议在Service
中进行,并处理自己的线程
@Override
public int onStartCommand(final Intent intent, int flags, final int startId)
{
new Thread(new Runnable() {
@Override
public void run() {
// handle your own media playing here...
}
}, "MplayerService").start();
...
}
如果您希望用户控制您的媒体播放器
我建议绑定服务here
来自文档的更多信息:
Service
服务是一个应用程序组件,表示应用程序希望在不与用户交互或为其他应用程序提供功能的情况下执行较长时间运行的操作使用。
IntentService
IntentService是服务的基类,可根据需要处理异步请求(表示为Intents)。客户端通过startService(Intent)调用发送请求;服务根据需要启动,使用工作线程依次处理每个Intent,并在工作失败时自行停止。