Browse Source

修复频繁按着松开奔溃问题

weicu
fdp 9 months ago
parent
commit
2061abb860
  1. 9
      lib/data/services/speech_impl/azure_asr_service.dart
  2. 18
      local_plugins/agent_service/lib/agent_service.dart
  3. 17
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/AudioRecordingForegroundService.kt

9
lib/data/services/speech_impl/azure_asr_service.dart

@ -252,12 +252,9 @@ class AzureAsrService extends GetxService implements AsrService {
/// - 若当前不在识别中,直接返回 true; /// - 若当前不在识别中,直接返回 true;
/// - 调用成功后立即将内部状态置为 false(同时事件通道回调仍会再次校正)。 /// - 调用成功后立即将内部状态置为 false(同时事件通道回调仍会再次校正)。
Future<bool> stopContinuousRecognition() async { Future<bool> stopContinuousRecognition() async {
// 防抖判断:短时间内重复调用直接拦截 // 移除防抖判断,确保停止操作总是被执行
final now = DateTime.now(); // 这与 AgentService 的逻辑保持一致,防止“松开还在录”的问题
if (_lastStopAt != null && now.difference(_lastStopAt!) < _debounce) { _lastStopAt = DateTime.now();
return false;
}
_lastStopAt = now;
if (!_isInitialized || !_isContinuousRecognitionActive) { if (!_isInitialized || !_isContinuousRecognitionActive) {
return true; return true;

18
local_plugins/agent_service/lib/agent_service.dart

@ -258,11 +258,17 @@ class AgentService {
if (_lastStartConversationAt != null && if (_lastStartConversationAt != null &&
now.difference(_lastStartConversationAt!) < _conversationDebounce) { now.difference(_lastStartConversationAt!) < _conversationDebounce) {
// 函数级注释:当在冷却时间内再次调用时,直接返回 false 表示此次调用被防抖拦截 // 函数级注释:当在冷却时间内再次调用时,直接返回 false 表示此次调用被防抖拦截
// 对于启动操作,如果被防抖拦截,意味着用户点击太快。
// 返回 false 是正确的,因为我们确实没有启动新的会话。
return false; return false;
} }
_lastStartConversationAt = now; _lastStartConversationAt = now;
try { try {
// 在启动新对话前,确保之前的对话已完全停止
// 这不仅可以清理状态,还能避免因快速切换导致的资源冲突
await stopConversation();
final bool result = await _channel.invokeMethod('startConversation', { final bool result = await _channel.invokeMethod('startConversation', {
'mode': mode, 'mode': mode,
}); });
@ -328,14 +334,10 @@ class AgentService {
/// 停止语音识别 /// 停止语音识别
/// 返回是否成功停止对话 /// 返回是否成功停止对话
static Future<bool> stopConversation() async { static Future<bool> stopConversation() async {
// 防抖:短时间内重复点击直接忽略(冷却式防抖) // 移除防抖拦截!
final now = DateTime.now(); // 停止操作是安全且必要的,不应该被拦截。
if (_lastStopConversationAt != null && // 即使频繁调用,Native 层也能处理(我们已经修复了 Native 层的并发问题)。
now.difference(_lastStopConversationAt!) < _conversationDebounce) { _lastStopConversationAt = DateTime.now();
// 函数级注释:当在冷却时间内再次调用时,直接返回 false 表示此次调用被防抖拦截
return false;
}
_lastStopConversationAt = now;
try { try {
final bool result = await _channel.invokeMethod('stopConversation'); final bool result = await _channel.invokeMethod('stopConversation');

17
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/AudioRecordingForegroundService.kt

@ -23,6 +23,7 @@ class AudioRecordingForegroundService : Service() {
private const val NOTIFICATION_ID = 1001 private const val NOTIFICATION_ID = 1001
private const val CHANNEL_ID = "audio_recording_channel" private const val CHANNEL_ID = "audio_recording_channel"
private const val CHANNEL_NAME = "音频录制服务" private const val CHANNEL_NAME = "音频录制服务"
private const val ACTION_STOP = "com.yunqiinnovation.azure_speech.tools.STOP_SERVICE"
/** /**
* 启动前台服务 * 启动前台服务
@ -44,8 +45,9 @@ class AudioRecordingForegroundService : Service() {
*/ */
fun stopService(context: Context) { fun stopService(context: Context) {
val intent = Intent(context, AudioRecordingForegroundService::class.java) val intent = Intent(context, AudioRecordingForegroundService::class.java)
context.stopService(intent) intent.action = ACTION_STOP
Log.d(TAG, "音频录制前台服务已停止") context.startService(intent)
Log.d(TAG, "发送停止音频录制前台服务指令")
} }
} }
@ -56,12 +58,21 @@ class AudioRecordingForegroundService : Service() {
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "AudioRecordingForegroundService onStartCommand") Log.d(TAG, "AudioRecordingForegroundService onStartCommand action=${intent?.action}")
// 创建前台通知 // 创建前台通知
val notification = createNotification() val notification = createNotification()
// 必须立即调用 startForeground 以满足 Android 8.0+ 的要求
startForeground(NOTIFICATION_ID, notification) startForeground(NOTIFICATION_ID, notification)
// 检查是否是停止指令
if (intent?.action == ACTION_STOP) {
Log.d(TAG, "收到停止指令,停止服务")
stopForeground(true)
stopSelf()
return START_NOT_STICKY
}
// 返回START_STICKY确保服务被系统杀死后会重启 // 返回START_STICKY确保服务被系统杀死后会重启
return START_STICKY return START_STICKY
} }

Loading…
Cancel
Save