【问题标题】:Cannot get android MediaPlayer onCompletion to fire无法让 android MediaPlayer onCompletion 触发
【发布时间】:2012-04-03 17:53:13
【问题描述】:

我正在尝试使用 android MediaPlayer 类播放一些声音。

这是代码

MediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
            public void onCompletion(MediaPlayer mp) { 
                Log.i(LOGTAG, "onComplete hit"); 
                mp.stop(); 
                mp.release(); 
            } 
    });         

mp.prepare(); 
mp.start();

此代码在服务中运行,但由于某种原因,声音播放正常,但放置在 onCompletion 中的任何内容似乎都没有触发。然后我在 logcat 中收到一条消息,指出媒体播放器没有发布。我不知道我有什么问题。

我正在 Galaxy nexus 4.0.4 stock rom 上运行此测试。

我还注意到声音在结尾处可能会被削波。

【问题讨论】:

标签: android android-mediaplayer


【解决方案1】:

这实际上很简单(但很愚蠢)。在调用 start() 后设置监听器,如下所示:

ediaPlayer mp = new MediaPlayer(); 
mp.setDataSource(context, Uri.parse(soundUrl)); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
mp.setLooping(false); 
mp.prepare(); 
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
    @Override 
            public void onCompletion(MediaPlayer mp) { 
                Log.i(LOGTAG, "onComplete hit"); 
                mp.stop(); 
                mp.release(); 
            } 
    });         

【讨论】:

  • 您能解释一下为什么在设置完成侦听器之前调用 start() 很重要吗?这是 Android 的怪癖吗?
  • @FabianTamp 这是另一个 Android 怪癖。所有设备(甚至不再需要)可能都不需要它,但当时它绝对是解决问题的方法。
  • 我看不到任何证据来支持为什么这会修复 Android 源代码中的问题。结果对我来说根本问题是MediaPlayer在播放完毕之前就被GC了,我添加了一个更详细概述的答案:)
  • 我不能再抱怨了,这救了我:)
【解决方案2】:

我是这样的:

    video.setOnCompletionListener(this);
    IntroClip.execute(video);
}

@Override
public void onCompletion(MediaPlayer mp){
    Button LoginButton;
    Button CreateAccount;
    Button RecoverPass;

    setContentView(R.layout.loginmenu);
    Spin = (ProgressBar)findViewById(R.id.Spinner);

    mp.release();       
}

【讨论】:

  • 我猜“video”是MediaPlayer的一个实例?并且您的班级中有一个“实现 MediaPlayer.OnCompletionListener”?这个方法我也试过了,还是不行。
  • @Andrew 如果它不起作用,它如何接受答案?你让它工作了吗?如果是,怎么做?
  • @smitalm 在设置监听器之前调用 start()。
【解决方案3】:

我遇到了与此类似的症状,根本原因是 MediaPlayer 在调用 OnCompletionListener 之前已被垃圾收集。

从您的代码来看,这似乎是同样的问题 - 您的代码没有对 MediaPlayer 的长期引用,因此一旦该函数结束(并且在音频播放完毕之前)MediaPlayer 很容易受到GC。

此日志行可识别此问题:

02-22 13:14:57.969: W/MediaPlayer-JNI(16888): MediaPlayer finalized without being released

您可以通过重新构建类来修复它,以便将 MediaPlayer 引用保留更长时间 - 例如,通过在 Activity 中存储对它的引用,并重复使用相同的实例来多次播放相同的声音。

这里有更详细的解释:Garbage Collection causes : MediaPlayer finalized without being released

【讨论】:

    【解决方案4】:

    其实原因是MediaPlayer是一个局部变量。该函数完成后,MediaPlayer 被 GC 收集。 所以修复很简单,让您的 MediaPlayer 成为该类的成员。

    YourClassName {
        MediaPlayer mp = new MediaPlayer(); 
    
        void YourFunction() {
              mp.setDataSource(context, Uri.parse(soundUrl)); 
              mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
              mp.setLooping(false); 
              mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
                  @Override 
                  public void onCompletion(MediaPlayer mp) { 
                      Log.i(LOGTAG, "onComplete hit"); 
                      mp.stop(); 
                      mp.release(); 
                  }
              });         
              mp.prepare(); 
              mp.start();
        }
    }
    

    【讨论】:

      【解决方案5】:

      有两种方法可以初始化 MediaPlayer 对象,“new”和“create()”。为了做OnCompletionListener,这两种方式获取的对象是不同的。

      1) “新”方法

      MediaPlayer mp = new MediaPlayer();
      mp.setDataSource(context, Uri.parse(soundUrl)); 
      mp.setAudioStreamType(AudioManager.STREAM_MUSIC); 
      mp.setLooping(false); 
      mp.prepare(); 
      mp.start();
      mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 
          @Override 
          public void onCompletion(MediaPlayer mp) { 
              Log.i(LOGTAG, "onComplete hit"); 
              mp.stop(); 
              mp.release(); 
          } 
      }); 
      

      2)“创建”方法

      MediaPlayer mp = MediaPlayer.create(getActivity(), Uri.parse(soundUrl));
      //mp.prepare() is not needed here
      mp.setLooping(false);
      mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
          @Override
          public void onCompletion(MediaPlayer mp) {
              Log.i(LOGTAG, "onComplete hit");
              mp.stop();
              mp.release();
          }
      });
      

      对于 create() 方法,我遇到了类似的问题。如果在调用 create() 之后调用 mp.prepare(),则该过程将永远不会到达后面的 setOnCompletionListener,甚至不会到达 start()。根本原因是“如果使用create方法创建成功,则对象处于Prepared状态”(https://developer.android.com/reference/android/media/MediaPlayer.html)。所以你不需要在使用 create() 方法后调用 prepare()。

      【讨论】:

        猜你喜欢
        • 2011-11-25
        • 2012-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-28
        相关资源
        最近更新 更多