Class Work<T>
- Type Parameters:
T- the type the body produces
onSuccess, onFailure and
onProgress run on the UI thread, so those handlers may touch widgets
directly. onDiscarded is the one exception and runs on the worker
pool (it disposes of a value the UI never sees, and disposing is allowed to
block), so a widget touched from there throws.
job = Ui.work(progress -> repository.load(id))
.onProgress(bar::setValue)
.onSuccess(list::setItems)
.onFailure(error -> status.setText(error.getMessage()))
.deliverIf(view::isShowing)
.start();
This is what Ui.async is not: the returned Job can be
cancelled, and a cancelled job delivers nothing, so a view that starts one
request per keystroke and cancels the previous one shows the answer to the
question last asked, rather than whichever answer arrived last.
Each setter replaces the handler it names rather than adding to it, and
null clears it. Register everything before start(): the
handlers are read once, when the job starts, and a setter called afterwards
has no effect on the job already running.
One job runs at most one terminal callback: onSuccess or
onFailure, never both and never twice. Whatever progress deliveries
survived coalescing precede it, and a cancelled job runs none of them.
-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptiondeliverIf(BooleanSupplier alive) Guards every delivery: asked on the UI thread immediately before each success, failure and progress callback, andfalsedrops that delivery exactly as cancellation would; a dropped result goes toonDiscarded.onDiscarded(Consumer<T> dispose) Disposes of a result that will never be delivered, the leak guard for a body that returns something holding an open resource.Receives whatever the body threw, on the UI thread, unwrapped: the throwable the body threw, not a wrapper around it.onProgress(DoubleConsumer handler) Receives values passed toProgress.report(double), on the UI thread, clamped to 0..1 and coalesced; seeProgress.report(double)for what that skips and what it guarantees.Receives the body's return value on the UI thread.start()Submits the body to the worker pool and returns its handle.
-
Method Details
-
onSuccess
Receives the body's return value on the UI thread. Not called at all if the job was cancelled, ifdeliverIf(java.util.function.BooleanSupplier)answeredfalse, or if the body threw.- Parameters:
handler- the receiver, ornullto drop the result- Returns:
- this, for chaining
-
onFailure
Receives whatever the body threw, on the UI thread, unwrapped: the throwable the body threw, not a wrapper around it.With no handler registered, a failure is logged at ERROR and reported to the process crash handler as a task crash rather than being swallowed. A job that was cancelled reports nothing at all, including its failure, on the grounds that a body usually fails because it was cancelled; that case is logged at DEBUG.
- Parameters:
handler- the receiver, ornullfor the log-and-report default- Returns:
- this, for chaining
-
onProgress
Receives values passed toProgress.report(double), on the UI thread, clamped to 0..1 and coalesced; seeProgress.report(double)for what that skips and what it guarantees.A delivery is a level, not an event. Most reported values are never delivered, and the body has already moved past the one that is, so a handler must use the number it is handed rather than count deliveries, accumulate them, or treat one as "a step finished".
- Parameters:
handler- the receiver, ornullto ignore reports- Returns:
- this, for chaining
-
onDiscarded
Disposes of a result that will never be delivered, the leak guard for a body that returns something holding an open resource.Called when the body produced a value and the job was cancelled, or
deliverIf(java.util.function.BooleanSupplier)answeredfalse. It runs on the worker pool, not on the UI thread, because it is cleanup of a value the UI never sees and it is allowed to block; the one exception is a pool already shut down, where the disposal runs on the calling thread rather than leaking. Without a handler the value is dropped silently, and a handler that throws is logged and does not propagate.It is not called when the body throws, because there is no value. It is called for a value the body produced and the job then withdrew, whether or not an
onSuccesswas ever registered, which is what lets a facade attach the disposer on its caller's behalf and have it hold for every caller. What is not disposed is a value that was delivered normally with no success handler to take it: nothing was withdrawn there, and a body whose result nobody wants should not be returning a resource.- Parameters:
dispose- the disposer, ornullto drop silently- Returns:
- this, for chaining
-
deliverIf
Guards every delivery: asked on the UI thread immediately before each success, failure and progress callback, andfalsedrops that delivery exactly as cancellation would; a dropped result goes toonDiscarded.This is how "the requester has gone away" is expressed without the job knowing what a requester is: pass a predicate over whatever owns the request, such as a widget's attached-to-a-scene state. It is asked once per delivery, so it must be cheap and must not block. A predicate that throws is logged and read as
false, so a broken guard drops and disposes rather than delivering into a half-torn-down view.A
truecovers that one delivery and nothing after it. Work a handler posts for a later frame is unguarded and has to ask again.- Parameters:
alive- asked on the UI thread, ornullto always deliver- Returns:
- this, for chaining
-
start
Submits the body to the worker pool and returns its handle. Safe to call from any thread.Jobs are not ordered against each other: two started in sequence complete in whichever order the pool and the work give them, so a view that must show the answer to the request last asked holds the earlier
Joband cancels it rather than relying on arrival order.Forgetting this call is the one silent failure the builder has, so a description that is garbage-collected without it logs one WARNING naming the omission; at DEBUG the message carries the stack that built it.
- Returns:
- the handle, already submitted; it may have run by the time this returns
- Throws:
IllegalStateException- if this description was already started; a second run is a second description
-