Class Ui
UiRuntime, Limn's first-class
async API. The backend installs the runtime at startup; application code
then uses:
button.onAction(() ->
Ui.async(() -> repository.load()) // worker pool
.thenAccept(data -> label.setText(data)) // back on the UI thread
);
Thread confinement is a hard rule: every widget mutation calls
checkUiThread() and throws IllegalStateException when
violated.
-
Method Summary
Modifier and TypeMethodDescriptionstatic <T> CompletionStage<T> Runsworkon the worker pool; the returned stage completes on the UI thread (including its default async executor).static voidstatic Executorexecutor()static voidInstalls the process-wide runtime.static booleanstatic booleanstatic voidRunsactionon the UI thread on the next frame.static voidpostDelayed(Runnable action, long delayMillis) Runsactionon the UI thread afterdelayMillis.static voidUninstallscandidateif it is the installed runtime (backend shutdown).static <T> Work<T> Describes background work with a lifecycle: cancellable, able to report progress, and able to decline delivery when whoever asked has gone away.
-
Method Details
-
install
Installs the process-wide runtime. Called by the backend once at startup.- Throws:
IllegalStateException- if a different runtime is already installed
-
uninstall
Uninstallscandidateif it is the installed runtime (backend shutdown). -
isInstalled
public static boolean isInstalled()- Returns:
- whether a runtime is installed (i.e. a Backend is running)
-
post
Runsactionon the UI thread on the next frame. Any-thread safe.A task that mutates widget or scene state is responsible for invalidating what it touched:
Widget.invalidate(),Widget.markNeedsLayout()orScene.requestRender(). Running a task buys no frame of its own, so a mutation nothing invalidates stays unpainted until something else asks for one. Every widget setter and every tree change invalidates already; a task that writes a field behind a setter's back, or that changes what a customonPaintreads, does not. -
postDelayed
Runsactionon the UI thread afterdelayMillis. Any-thread safe.A task that mutates widget or scene state is responsible for invalidating what it touched: see
post(java.lang.Runnable). Firing buys no frame of its own, which is what makes a timer the cheap way to watch something that rarely changes: a poll that re-reads a value and finds it unchanged costs a wake-up and nothing else, where atickerasks for a frame every frame it stays registered. -
async
Runsworkon the worker pool; the returned stage completes on the UI thread (including its default async executor).A dependent that mutates widget or scene state is responsible for invalidating what it touched: see
post(java.lang.Runnable). Completing on the UI thread buys no frame;label.setText(data)asks for the frame that shows it, a field written directly does not. -
work
Describes background work with a lifecycle: cancellable, able to report progress, and able to decline delivery when whoever asked has gone away. Nothing runs untilWork.start():job = Ui.work(progress -> repository.search(term)) .onSuccess(results::setItems) .deliverIf(results::isAttached) .start();Reach for this over
async(java.util.function.Supplier<T>)whenever the request can be superseded: cancelling the previous job means the view shows the answer to the question last asked, rather than whichever answer happened to finish last. -
isUiThread
public static boolean isUiThread()- Returns:
trueiff called on the UI thread (false when no runtime is installed)
-
checkUiThread
public static void checkUiThread()- Throws:
IllegalStateException- if not on the UI thread (or no runtime installed)
-
executor
- Returns:
- an executor that posts to the UI thread
-