pythonkivy

Kivy GUI freezes after 10s interval


I have an app, collects WiFi and Bluetooth signals and displays them onto a Label in a RecycleView. When a Start Scan button is pressed, we collect the data from an Android device and update Label.text. The scan is then next carried out on a 10 second interval, GUI freezes for a brief moment, new data is appended to the Label and it keeps going.

def start_scanning(self, instance):
    self.scan_network()
    self.scan_event = Clock.schedule_interval(self.scan_network, 10)

The self.scan_event is there for us to be able to stop or .cancel network scan.

The understanding of Kivy I posses is that GUI is on a MainThread. Because our scan happens on a MainThread that leads to GUI freeze correct? Therefore, we need our scans to be carried out on a Thread although when I do try to get scans to be on another Thread it doesn't seem to work.

I'm pretty sure the issue is the Clock.schedule_interval. We could have the label being continously updated in another Thread but on a interval would be preferred for now. How could I possibly unfreeze GUI?

Possibly is there a threading.Timer way to replace Clock.schedule_interval?

Let me know, if more reproducible example is required.

Edit: A more reproducible example was provided.

# 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() 

Solution

  • As per @JohnAnderson suggestion, we've went along with Threading for our scan_network however, individual Threads for individual scans don't appear to wokr at the moment.

    We've also used @mainthread decorator on the update_text so that we can update the value from different Thread without slowing out the MainThread.