我有一个应用程序,收集 WiFi 和蓝牙信号并将其显示在
Label
中的 RecycleView
上。当按下 Start Scan
按钮时,我们会从 Android 设备收集数据并更新 Label.text
。接下来,每隔 10 秒进行一次扫描,GUI 会短暂冻结,新数据会附加到标签上,然后继续扫描。
def start_scanning(self, instance):
self.scan_network()
self.scan_event = Clock.schedule_interval(self.scan_network, 10)
self.scan_event
让我们能够停止或.cancel
网络扫描。
我对Kivy的理解是GUI是在
MainThread
上。因为我们的扫描发生在 MainThread
上,导致 GUI 冻结,正确吗?因此,我们需要在一个线程上执行扫描,尽管当我尝试在另一个线程上进行扫描时,它似乎不起作用。
我很确定问题是
Clock.schedule_interval
。我们可以让标签在另一个线程中持续更新,但目前最好每隔一段时间更新。我怎样才能解冻 GUI?
可能有
threading.Timer
的方法来代替Clock.schedule_interval
吗?
如果需要更多可重现的示例,请告诉我。
编辑:提供了一个更具可重复性的示例。
# This here updates the text in a label after scan_wifi or scan_bluetooth call this function to feed found network information
@mainthread
def update_text(self, new_results):
self.scanned_results = new_results + self.scanned_results
self.results_area.data = [{'text':str(result)} for result in self.scanned_results]
def get_wifi(self, *args):
# some logic
def get_bluetooth(self, *args):
# some logic
def scan_network(self, *args):
self.get_bluetooth()
self.get_wifi()
def start_scanning(self, instance):
self.scan_network()
# This here runs the function again but on interval my guess is this is what is freezing it.
self.scan_event = Clock.schedule_once(self.scan_network, 10)
# This function is called when on_press in a button.
def toggle_scan(self, *args):
# [...]
# above here we have some stopping logic
self.start_scanning(*args)
# These kinda work but after the first interval wave only mainthread appears and thread-1 just seems to hang there.
# with concurrent.futures.ThreadPoolExecutor() as self.executor:
# self.executor.submit(self.get_bluetooth)
# self.executor.submit(self.get_wifi)
# t = threading.Thread(target=self.start_scanning, args=(args))
# t.daemon = True
# t.start()
# t.join()
根据@JohnAnderson的建议,我们已经为我们的
scan_network
使用了线程,但是,用于单个扫描的单个线程目前似乎无法工作。
我们还在
@mainthread
上使用了 update_text
装饰器,这样我们就可以更新来自不同线程的值,而不会减慢 MainThread
的速度。