9.5 KiB
9.5 KiB
语音测评闪退问题排查与解决方案
🔍 问题描述
App运行语音测评时经常闪退,尤其是在导入数据时更容易发生。
📊 问题分析
可能原因1:内存不足
-
语音模型文件较大
- vosk-model-small-cn-0.22.zip 约50-100MB
- 首次解压需要大量内存
- 解压时间约30秒
-
导入数据同时运行
- 如果正在导入大量学员数据
- 同时运行语音识别
- 内存可能不足导致崩溃
可能原因2:页面切换时回调未停止
-
回调函数继续执行
- 页面卸载后,语音识别回调可能继续执行
- 访问已销毁的组件实例导致崩溃
-
状态检查不严格
- 只检查
isRecording状态 - 没有检查页面是否已卸载
- 只检查
可能原因3:数据导入错误影响系统
-
班级不存在
- 导入的学员数据包含不存在的班级
- 后端返回错误,前端处理不当
-
数据格式错误
- Excel格式不符合要求
- 必填字段为空
可能原因4:模型初始化失败
- 模型文件损坏或缺失
- 路径解析错误
- 权限问题
✅ 解决方案
方案1:优化页面生命周期(已修复)
添加页面卸载标记
data() {
return {
// ... 其他数据
pageUnloaded: false // 页面卸载标记
}
}
在onUnload中设置标记
onUnload() {
console.log('[Speech] 页面卸载,清理资源')
// 标记页面已卸载,防止回调继续执行
this.pageUnloaded = true
// 停止语音识别
if (this.isRecording) {
this.isRecording = false
try {
if (typeof stopSpeechVoice === 'function') {
stopSpeechVoice()
}
} catch(e) {
console.error('[Speech] 停止识别时出错:', e)
}
}
// 清理定时器
this.stopAutoScroll()
if (this.scrollTimer) {
clearInterval(this.scrollTimer)
this.scrollTimer = null
}
}
添加onHide生命周期
onHide() {
console.log('[Speech] 页面隐藏,暂停识别')
// 页面切换到后台时停止识别
if (this.isRecording) {
this.handleStop()
}
}
在回调中检查页面状态
startSpeechVoice((res) => {
// 检查页面是否已卸载
if (self.pageUnloaded) {
console.log('[Speech] 页面已卸载,忽略回调')
return
}
// 检查是否仍在录音状态
if (!self.isRecording) {
console.log('[Speech] 已停止录音,忽略回调')
return
}
// ... 处理识别结果
})
方案2:修复数据导入(已修复)
班级验证
- ✅ 在导入前验证班级是否存在
- ✅ 班级不存在时,记录失败原因
- ✅ 不中断整个导入流程
错误处理
- ✅ 导入失败的记录单独显示
- ✅ 提供详细的失败原因
- ✅ 失败详情支持滚动查看
生成测试数据
- ✅ 使用
generate_test_data.py生成符合要求的测试数据 - ✅ 所有字段自动标准化为系统选项
- ✅ 班级自动映射到系统实际班级
方案3:优化语音模型加载
延迟加载
onLoad(options) {
// 先加载内容列表
if (options.contentId) {
this.loadContentById(options.contentId)
} else {
this.loadContentList()
}
// 延迟1秒后再初始化模型
setTimeout(() => {
// #ifdef APP-PLUS
this.initSpeechModel()
// #endif
}, 1000)
}
检查内存
initSpeechModel() {
// 检查可用内存(如果API支持)
// #ifdef APP-PLUS
try {
const memInfo = plus.device.getInfo()
console.log('[Speech] 设备内存信息:', memInfo)
} catch(e) {
console.log('[Speech] 无法获取内存信息')
}
// #endif
// ... 继续初始化
}
方案4:添加错误捕获
全局错误处理
// App.vue 或 main.js
uni.onError((error) => {
console.error('[Global] 全局错误:', error)
// 可以记录到后端日志
// 显示友好的错误提示
uni.showToast({
title: '应用出错,请重启',
icon: 'none',
duration: 3000
})
})
Try-Catch包裹关键代码
async evaluateScore() {
if (!this.recognizedText || !this.selectedContent) {
uni.showToast({ title: '请先完成语音识别', icon: 'none' })
return
}
this.isEvaluating = true
try {
const result = await evaluateSpeechRecognition(
this.selectedContent.content,
this.recognizedText
)
if (result.code === 200 && result.data) {
this.scoreResult = result.data
await this.saveScoreToBackend(result.data)
uni.showToast({ title: '评分完成', icon: 'success', duration: 2000 })
} else {
throw new Error(result.msg || '评分失败')
}
} catch (error) {
console.error('评分失败', error)
uni.showToast({
title: error.message || '评分失败,请重试',
icon: 'none',
duration: 3000
})
} finally {
this.isEvaluating = false
}
}
🧪 测试步骤
1. 测试页面切换
- 打开语音测评页面
- 开始语音识别
- 立即返回首页
- 观察是否崩溃
预期结果: ✅ 不崩溃,识别自动停止
2. 测试数据导入
- 准备100条测试数据
- 在语音测评页面
- 同时执行数据导入
- 观察是否崩溃
预期结果: ✅ 不崩溃,两个操作互不影响
3. 测试模型加载
- 清除模型缓存
- 重新打开语音测评
- 等待模型加载
- 观察是否崩溃
预期结果: ✅ 不崩溃,正常加载
4. 测试长时间识别
- 开始语音识别
- 持续朗读3分钟
- 观察是否崩溃
预期结果: ✅ 不崩溃,正常识别
📋 使用建议
避免同时操作
- ❌ 不要在导入数据时使用语音测评
- ❌ 不要在语音识别时导入大量数据
- ✅ 先完成一个操作,再进行另一个
分批导入数据
- ✅ 每次导入不超过50条
- ✅ 等待上一批导入完成再导入下一批
- ✅ 避免一次性导入过多数据
定期清理缓存
- ✅ 在设置中清理应用缓存
- ✅ 清理语音模型缓存后重新加载
- ✅ 卸载重装应用(如果频繁崩溃)
检查设备
- ✅ 确保设备有足够的可用内存(至少500MB)
- ✅ 关闭其他占用内存的应用
- ✅ 重启设备
🔧 调试方法
1. 查看控制台日志
# HBuilderX中查看真机运行日志
# 搜索关键字:[Speech]、Error、crash
2. 查看后端日志
# 查看后端日志,是否有错误
tail -f logs/app.log | grep ERROR
3. 使用测试数据
# 生成测试数据
python generate_test_data.py
# 导入测试数据,观察是否正常
4. 逐步排查
-
不使用语音测评 - 只导入数据
- 如果正常:语音测评有问题
- 如果崩溃:数据导入有问题
-
不导入数据 - 只使用语音测评
- 如果正常:数据导入影响了语音测评
- 如果崩溃:语音测评本身有问题
-
清除数据 - 卸载重装应用
- 如果正常:缓存数据有问题
- 如果崩溃:代码或资源文件有问题
💡 优化建议
1. 按需加载模型
- 不在onLoad中自动初始化
- 用户点击"开始说话"时才加载
- 显示"模型加载中"提示
2. 使用更小的模型
- 当前使用 vosk-model-small-cn-0.22
- 可以使用更小的模型(如果存在)
- 或者使用在线API(需要网络)
3. 优化数据导入
- 使用分批导入(每批20-30条)
- 显示导入进度
- 支持后台导入
4. 添加异常恢复
- 崩溃后自动保存状态
- 重新打开时恢复上次状态
- 提供"恢复上次会话"功能
✅ 验收标准
- 页面快速切换不崩溃
- 导入数据时不崩溃
- 长时间语音识别不崩溃
- 模型加载失败有友好提示
- 数据导入失败有详细错误信息
- 控制台无严重错误日志
- 内存占用在合理范围内
📝 修改文件清单
已修改
-
✅
fronted_uniapp/pages/speech/speech.vue- 添加
pageUnloaded标记 - 添加
onHide生命周期 - 回调中检查页面状态
- 添加
-
✅
Study-Vue-redis/ry-study-ui/src/views/study/classUser/index.vue- 导入失败对话框添加滚动条
-
✅
Study-Vue-redis/ry-study-admin/.../StudyClassUserController.java- 移除导入前的班级验证
-
✅
Study-Vue-redis/ry-study-system/.../StudyClassUserServiceImpl.java- 添加逐条班级验证
- 记录失败原因到错误信息
新增文件
- ✅
generate_test_data.py- 测试数据生成脚本
🎯 总结
核心问题
- 页面卸载后回调继续执行
- 数据导入和语音识别同时进行
- 内存不足
解决方法
- 严格的生命周期管理
- 状态检查
- 分批操作
- 错误处理
使用建议
- 避免同时操作
- 定期清理缓存
- 使用测试数据验证
现在请测试修复后的版本,观察是否还会闪退! 🚀