我正在开发一款Android应用,通过在屏幕上显示消息并同时使用TextToSpeech
进行阅读,让用户了解他们的进度。为了保持视觉和听觉刺激的同步,我倾听Done
事件。但是,我发现在经过一段时间(通常在20到40分钟之间)之后,内存压力导致Android开始查杀进程,并最终导致语音服务死亡。在logcat中,我看到了像
I/ActivityManager( 565): Process com.google.android.tts (pid 7546) has died
有时我可以检测到这一点,因为当我致电Speak
时,它会返回OperationResult.Error
。然而,偶尔它会远远地提升Start
事件但随后死亡,并且从不提出任何其他事情。 logcat显示
I/TTS (11462): @636468802271461960: Speak(...) returned Success
I/TTS (11462): @636468802271474010: Start utterance88
I/TextToSpeech(11462): Asked to disconnect from ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService}
I/TextToSpeech(11462): Connected to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService}
I/TextToSpeech(11462): Set up connection to ComponentInfo{com.google.android.tts/com.google.android.tts.service.GoogleTTSService}
(前两行来自我的听众,见下文)。
通过public source code for TextToSpeech
查看我发现它通过活页夹检测到该过程的死亡并重新连接,但我看不到任何要通知的挂钩,我无法看到自己访问活页夹(除了使用反射来破解对私有字段的访问,这不是一个好的做法)。
当包装的语音服务重置时,是否有任何方法可以通知,或者我是否只需要添加大量的超时?
(代码在C#中,因为我使用的是Xamarin for Android,但是如果你能阅读那些不应该成为问题的Java)。
public class TTSProgressListener : UtteranceProgressListener, IDisposable
{
protected internal TTSProgressListener(TextToSpeechWrapper wrapper)
{
_TTS = wrapper ?? throw new ArgumentNullException(nameof(wrapper));
}
private readonly TextToSpeechWrapper _TTS;
#region UtteranceProgressListener
public override void OnStart(string utteranceId)
{
Android.Util.Log.Info("TTS", $"@{DateTime.Now.Ticks}: Start {utteranceId}");
}
public override void OnDone(string utteranceId)
{
Android.Util.Log.Debug("TTS", $"@{DateTime.Now.Ticks}: Utterance {utteranceId} finished");
_TTS.RaiseUtteranceFinished(utteranceId);
}
public override void OnError(string utteranceId)
{
Android.Util.Log.Warn("TTS", $"@{DateTime.Now.Ticks}: Utterance {utteranceId} errored");
// Treat as finished to avoid the situation where a missing voice can lock the entire system. (Believed to have occurred on one test tablet).
_TTS.RaiseUtteranceFinished(utteranceId);
}
#endregion
}