前段时间,我发现playEarcon()
永远不会产生 onUtteranceCompleted()
.
当时,我只是将“在合成话语时调用”的文档解释为onUtteranceCompleted()
不适用于耳控,因为耳控并不是 TTS 合成的真正结果。
但是再次查看 Android 的源代码,我根本找不到可以证明我的解释合理的解释。
关于我的测试夹具的一些事实:
onUtteranceCompleted()
总是在 earcon 之前到达话语 ID。该话语是普通的 TTS 话语,而不是耳标。- 之后的earcon确实发挥了作用(即完全符合预期)。
onUtteranceCompleted()
因为那个耳标永远不会出现。这是非常一致且可重现的行为。
深入研究 TtsService 源代码,似乎只有 2 种方法会影响 的到达(或不存在)onUtteranceCompleted()
:
如果您检查该代码,您将看到第三个候选者 TtsService.getSoundResource()被排除在外(因为我的earcon 缺少 onUtteranceComplete 负责),因为上面的事实#2:earcon 总是播放,因此getSoundResource()
不可能返回空值。
使用相同的逻辑,也可以排除第一个候选者 TtsService.processSpeechQueue() ,因为相同的事实 #2:earcon 始终播放,因此始终执行以下 2 个关键语句:
1108 mPlayer.setOnCompletionListener(this);
...
1111 mPlayer.start();
所以,我们只剩下第二个候选者,TtsService.onCompletion(),作为为什么 aplayEarcon()
从不产生 onUtteranceCompleted()
的可能解释:
public void onCompletion(MediaPlayer arg0) {
// mCurrentSpeechItem may become null if it is stopped at the same
// time it completes.
SpeechItem currentSpeechItemCopy = mCurrentSpeechItem;
if (currentSpeechItemCopy != null) {
String callingApp = currentSpeechItemCopy.mCallingApp;
ArrayList<String> params = currentSpeechItemCopy.mParams;
String utteranceId = "";
if (params != null) {
for (int i = 0; i < params.size() - 1; i = i + 2) {
String param = params.get(i);
if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)) {
utteranceId = params.get(i + 1);
}
}
}
if (utteranceId.length() > 0) {
dispatchUtteranceCompletedCallback(utteranceId, callingApp);
}
}
processSpeechQueue();
}
在那里,只有 2 个条件无法产生dispatchUtteranceCompletedCallback():
- currentSpeechItemCopy == null
- utteranceId.length() == 0
但我确信可以排除条件 #2,因为我记录了所有 utteranceIds 并且耳标肯定存在。
此外,检查整个系统日志:
Log.v(SERVICE_TAG, "TTS callback: dispatch started");
丢失onUtteranceCompleted()
可能是dispatchUtteranceCompletedCallback()没有被调用的结果,但也可能是mCallbacksMap.get(packageName)
返回 null 的结果。
所以,我们再次留下了两种可能性,这两种可能性对我来说都没有多大意义:
- 在调用 earcon 的onCompletion()时,earcon 的
mCurrentSpeechItem
值为空。但是为什么? - mCallbacksMap为空。它是什么,它什么时候被填充?
解决这个谜团的任何建议或其他解释?