Async apps
Flet app can be written as an async app and use asyncio
and other Python async libraries. Calling coroutines is naturally supported in Flet, so you don't need to wrap them to run synchronously.
By default, Flet executes control event handlers in separate threads, but sometimes that could be an ineffective usage of CPU or it does nothing while waiting for a HTTP response or executing sleep()
.
Asyncio, on the other hand, allows implementing concurrency in a single thread by switching execution context between "coroutines". This is especially important for apps that are going to be published as static websites using Pyodide. Pyodide is a Python runtime built as a WebAssembly (WASM) and running in the browser. At the time of writing it doesn't support threading yet.
Getting started with async
You could mark main()
method of Flet app as async
and then use any asyncio API inside it:
import flet as ft
async def main(page: ft.Page):
await asyncio.sleep(1)
page.add(ft.Text("Hello, async world!"))
ft.app(main)
You can use await ft.app_async(main)
if Flet app is part of a larger app and called from async
code.
Control event handlers
Control event handlers could be both sync and async
.
If a handler does not call any async methods it could be a regular sync method:
def page_resize(e):
print("New page size:", page.window_width, page.window_height)
page.on_resize = page_resize
However, if a handler calls async logic it must be async too:
async def main(page: ft.Page):
async def button_click(e):
await some_async_method()
page.add(ft.Text("Hello!"))
page.add(ft.ElevatedButton("Say hello!", on_click=button_click))
ft.app(main)
Async lambdas
There are no async lambdas in Python. It's perfectly fine to have a lambda event handler in async app for simple things:
page.on_error = lambda e: print("Page error:", e.data)
but you can't have an async lambda, so an async event handler must be used.
Sleeping
To delay code execution in async Flet app you should use asyncio.sleep()
instead of time.sleep()
, for example:
import asyncio
import flet as ft
def main(page: ft.Page):
async def button_click(e):
await asyncio.sleep(1)
page.add(ft.Text("Hello!"))
page.add(
ft.ElevatedButton("Say hello with delay!", on_click=button_click)
)
ft.app(main)
Threading
To run something in the background use page.run_task()
. For example, "Countdown" custom control which is self-updating on background could be implemented as following:
import asyncio
import flet as ft
class Countdown(ft.Text):
def __init__(self, seconds):
super().__init__()
self.seconds = seconds
def did_mount(self):
self.running = True
self.page.run_task(self.update_timer)
def will_unmount(self):
self.running = False
async def update_timer(self):
while self.seconds and self.running:
mins, secs = divmod(self.seconds, 60)
self.value = "{:02d}:{:02d}".format(mins, secs)
self.update()
await asyncio.sleep(1)
self.seconds -= 1
def main(page: ft.Page):
page.add(Countdown(120), Countdown(60))
ft.app(main)