【问题标题】:Setting event listener in a thread在线程中设置事件监听器
【发布时间】:2017-02-16 07:57:09
【问题描述】:

我开始一个新线程来播放音频。在run方法的开始,我首先创建了一个audiotrack。然后我设置audioTrack.setPlaybackPositionUpdateListeneraudiotrack播放完音频后做一些事情。最后,我打电话给audiotrack.write() 来实际播放音频。

代码 sn-p 在下面:

@Override
public void run() {
audioTrack = new  AudioTrack(listenerService.m_amAudioManager.STREAM_VOICE_CALL, listenerService.sampleRate, AudioFormat.CHANNEL_OUT_MONO, listenerService.audioFormat, listenerService.minBufSize / 8, AudioTrack.MODE_STREAM);
audioTrack.setPlaybackPositionUpdateListener(new  AudioTrack.OnPlaybackPositionUpdateListener() {
    @Override
    public void onMarkerReached(AudioTrack track) {
        endReached();
    }
});
audioTrack.play();
audioTrack.setNotificationMarkerPosition(959);
audioTrack.write(rReadShortBuffer, 0, rReadShortBuffer.length);
audioTrack.flush();
}

public void endReached(){
....

}

我的问题是我希望reachEnd() 方法将在创建audiotrack 的同一线程中执行。因为事件监听器属于audiotrack,而audiotrack 是在这个线程中产生并设置该事件的。所以所有的东西都应该包含在这个线程中。这对我来说很有意义。但是程序并没有按照预期的方式运行。创建audiotrack 的线程似乎在执行run() 方法内的所有代码后终止,然后在main 线程中执行reachEnd 方法。

你们知道这种行为的原因以及如何使endReached 在与创建audiotrack 的线程相同的线程中触发吗?非常感谢任何帮助!

【问题讨论】:

  • 播放确实到达了标记,因为我可以调试到侦听器事件(endReached)。但后来我发现当前线程在主 ui 线程中。可能是因为创建音轨的线程在 run 方法中执行完所有代码后已经终止,并且没有循环或睡眠来阻止它。
  • @pskink,你认为创建音轨的线程一旦运行到运行结束方法就会立即终止。所以当播放事件触发时,由于找不到创建音轨的原始线程,系统会将事件交给主ui线程处理。
  • @pskink,我的网络好像有问题。我无法访问 pastebin.com。现在我正在设法使用处理程序和活套。完成后我会告诉你结果。
  • 非常感谢。让我试一试。
  • @pskink,它失败了。播放事件仍然在主 ui 线程中触发。我要试试yosriz的方法。完成后我会告诉你的。

标签: java android multithreading audiotrack


【解决方案1】:

这是因为您的线程没有 Looper,(例如 HandlerThread)。 虽然文档没有说明这一点,但如果创建AudioTrack 的线程没有LooperAudioTrack 将使用主循环器,这意味着事件将安排在主线程的Handler 上,并且将在主线程上触发。

【讨论】:

  • 我发现文档说在我的情况下,该事件将在创建音轨的同一线程中触发。这个问题是否可能是由于播放事件被触发时线程已经终止引起的。所以系统将事件交给主 ui 线程来处理。你能解释一下如何为这个线程设置 looper 的更多细节吗?我认为这很有道理,但我有点困惑如何实现这个想法。
  • 将其设置为创建音轨的线程是正确的,但没有说明这取决于线程是否具有Looper(您可以看到需要Handler的第二个重载的线索,即 AudioTrack 需要 Handler 来触发事件,而简单的线程只是没有 Handler。
  • 关于如何做到这一点,请阅读handler/looper,您可以按照上面的建议使用HandlerThread,创建带有looper的线程。基本上Looper/Handler就是线程有消息队列,这个线程上的每个动作都是按顺序发生的,才能到达队列,这就是main/UI线程的操作方式,你需要一个这样工作的后台线程。跨度>
  • 谢谢。 Handler 和 looper 在这种情况下工作得很好。它们为普通线程增加了如此多的力量。
猜你喜欢
  • 1970-01-01
  • 2020-02-26
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多