Kivy界面调用语音识别函数时冻结,求多任务并行处理方案
解决Kivy语音识别时界面冻结的问题
问题根源
你的voice2text()方法在主线程中执行,里面的while True循环和r.listen()都是阻塞操作,会占用主线程导致Kivy界面无法响应其他交互(比如点击out按钮)。Kivy的UI更新和事件处理完全依赖主线程,因此必须把耗时/阻塞的任务放到独立子线程中运行。
解决方案:用多线程分离语音识别任务
使用Python的threading模块将语音识别逻辑放到子线程,让主线程专注处理UI交互。同时修正代码中的其他错误(文件操作、屏幕名称引用等),确保功能正常运行。
修改后的完整代码
from kivy.app import App from kivymd.uix.screen import Screen from kivy.uix.screenmanager import ScreenManager, Screen from kivymd.uix.textfield import MDTextField from kivy.lang import Builder from kivy.uix.label import Label from kivymd.uix.button import MDRectangleFlatButton from kivy.core.window import Window from kivymd.app import MDApp from kivymd.uix.label import MDLabel import speech_recognition as sr from kivy.clock import Clock from kivy.uix.scrollview import ScrollView import threading # 导入线程模块 Window.size=(300,500) class Menuscreen(Screen): pass class ButtonONEScreen(Screen): pass class MopScreen(Screen): pass # kivy code screen_helper = """ ScreenManager: id: screen_manager Menuscreen: ButtonONEScreen: MopScreen: <Menuscreen>: name:"menu" MDRectangleFlatButton: text: 'ButtonONE' pos_hint: {'center_x':0.5,'center_y':0.6} on_press: root.manager.current = 'ONE' <ButtonONEScreen>: name: 'ONE' MDRectangleFlatButton: text: 'START' id: START_button pos_hint: {'center_x':0.2,'center_y':0.1} on_release: app.start_voice_recognition() # 改为启动线程的方法 MDRectangleFlatButton: text: 'back' id: back pos_hint: {'center_x':0.5,'center_y':0.1} on_release: root.manager.current="menu" MDRectangleFlatButton: text: 'out' id: out_button pos_hint: {'center_x':0.8,'center_y':0.1} on_release: app.text() root.manager.current= "mainout" <MopScreen>: name: "mainout" ScrollView: # 添加滚动视图,避免文本过长显示不全 MDLabel: id: mylabel size:self.texture_size size_hint_y: None text: "" MDRectangleFlatButton: text: 'back' id: back pos_hint: {'center_x':0.7,'center_y':0.1} on_release: root.manager.current="menu" """ # python code class TestApp(MDApp): def __init__(self, **kwargs): self.title = "v2t App" self.voice_thread = None # 保存线程对象 self.is_recognizing = False # 标记是否正在识别 super().__init__(**kwargs) def build(self): sm = Builder.load_string(screen_helper) return sm def start_voice_recognition(self): # 避免重复启动线程 if not self.is_recognizing: self.is_recognizing = True self.voice_thread = threading.Thread(target=self.voice2text) self.voice_thread.daemon = True # 守护线程,退出APP时自动结束 self.voice_thread.start() def voice2text(self): r = sr.Recognizer() while self.is_recognizing: # 用标记控制循环,方便后续扩展停止功能 try: with sr.Microphone() as source: audio = r.listen(source, 10, 4) text = r.recognize_google(audio) print(text) # 用with语句自动关闭文件,避免资源泄漏 with open("words.txt", "a", encoding="utf-8") as file: file.write(text + "\n") except sr.UnknownValueError: print("无法识别语音") except sr.RequestError as e: print(f"请求识别服务失败: {e}") except Exception as e: print(f"发生错误: {e}") self.is_recognizing = False def text(self): # 先取消之前的调度,避免重复执行 Clock.unschedule(self.callback) Clock.schedule_interval(self.callback, 0.5) def callback(self, dt): try: with open("words.txt", "r", encoding="utf-8") as file: load_file = file.read() # 修正屏幕名称:MopScreen的name是"mainout",不是"out" self.root.get_screen("mainout").ids.mylabel.text = load_file except FileNotFoundError: self.root.get_screen("mainout").ids.mylabel.text = "暂无识别内容" TestApp().run()
关键修改说明
多线程实现:
- 新增
start_voice_recognition()方法启动语音识别子线程,避免阻塞主线程 - 将
voice2text()放到子线程执行,设置为守护线程确保APP退出时自动终止 - 用
is_recognizing标记控制循环,方便后续扩展停止识别功能
- 新增
代码错误修复:
- 修正Kivy语言中
out按钮的缩进错误 - 修正
callback()方法中屏幕名称引用错误(将"out"改为"mainout") - 优化文件操作,使用
with语句自动关闭文件,避免资源泄漏
- 修正Kivy语言中
界面体验优化:
- 给
MopScreen添加ScrollView,避免识别文本过长无法完整显示 - 调用
text()时先取消之前的调度,避免重复执行更新逻辑
- 给
内容的提问来源于stack exchange,提问作者Romieo
相关产品推荐
相关产品推荐

