【问题标题】:Play mp3 Android async. Plays but then crashes thread播放 mp3 Android 异步。播放但随后崩溃线程
【发布时间】:2014-08-19 04:27:03
【问题描述】:

我需要在我的 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 断开了。

黑客修复

通过在我的线程开始处执行此操作:

        MediaPlayer objMediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.beeplow);

然后每次我想播放短哔声时,我都会这样做:

                    if(objMediaPlayer.isPlaying()){
                        objMediaPlayer.stop();
                        objMediaPlayer.release();
                        objMediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.beeplow);
                    }
                    objMediaPlayer.start();

似乎有效。天哪,代码太丑了,形式也很糟糕,但是,我只想播放 $** 声音,而不需要花费数小时和数百行代码!疯狂。

正确修复???

以下似乎有效。希望这是正确的方法......当我看到其他解决方案时,它们似乎是隐藏在服务等中的 50 多行代码等等。我喜欢下面的这个......如果这是正确的触发线程的方式我会在任何地方都这样做!

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            MediaPlayer objMediaPlayer = MediaPlayer.create(getBaseContext(),R.raw.beeplow);
                            objMediaPlayer.start();
                        }
                    }, "PlayBeepLow").start();

【问题讨论】:

    标签: android multithreading audio


    【解决方案1】:

    向死线程上的处理程序发送消息

    IntentService 中这样做是不安全的,因为它会在工作结束时自行停止。

    以上所有代码都在 Intent Service 的线程中调用... 所以它已经与 UI 完全断开了。

    处理完所有请求后,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 是按需处理异步请求(表示为 Intent)的服务的基类。客户端通过 startService(Intent) 调用发送请求;服务根据需要启动,使用工作线程依次处理每个 Intent,并在工作结束时自行停止。

    希望有帮助。

    【讨论】:

    • Intent 服务永远运行......好吧,直到 Android 决定终止它......但是,是的,它应该无休止地运行,收集蓝牙数据。在手机锁定的情况下测试了 5 小时没有问题。只是通过尝试播放声音,while 线程就死了。我会尝试使用您的新 Thread(.. 代码来触发声音。它只是在新数据进入时发出哔哔声,没什么花哨的,没有用户界面。谢谢 :-)
    • 线程解决方案有效...不确定我是否正确,但它有效。
    • 很高兴它有帮助! ,我也在我的服务中做一个线程,它在不到 10 秒的时间内接收到 100 多条消息,并将消息用作需要 ui 线程的地图中的数据,这就是为什么我需要一个长时间运行的服务来创建一个线程并创建广播接收器进行发送等。它在有 ANR 时解决了我的问题。我很高兴它也适合你。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-16
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多