Platform#runLater Question
Mark Fortner
phidias51 at gmail.com
Tue Apr 2 10:17:30 PDT 2013
Here's the genesis of the original question, this may give you some ideas
for the future.
I have an app where initially I had a lot of point-to-point event
listening. I created a generic event helper -- basically a mixin with an
executor to let me easily add event support to any class. I then realized
that what I really wanted was to centralize all event management in a
single place within my app. The main reason for this was that it becomes
very easy to lose track of who's listening to what when that code is
scattered throughout a project. So, I created an event manager, added it
to my application context so that I could easily access it from anywhere in
my code, and added the event helpers to the event manager.
Ultimately, the use cases that I'd like to cover cleanly are:
MyContext.fireEvent(event) // lets you fire an event, and notify all
relevant listeners
MyContext.addListener(eventHandler, eventType...) // let a listener listen
to a variety of event types
MyContext.removeListener(event, eventType...) // remove the listener from
the event types
I haven't yet figured out a clean way of removing listeners. It would be
nice if components had a life cycle with a "destructor" to let them do this
kind of cleanup. I don't think *finalize()* is the appropriate place to
take care of things like that. Perhaps by making *WeakListeners*, this
problem might go away on it's own and no specific "removeListener" method
is necessary.
I'm also planning on making the event helpers Spring-configurable so that
it's easy to tune the performance of specific types of events. I have some
events that trigger immediate responses in the GUI, and others that happen
in the background and only require the GUI to update when they complete
(either onSuccess, or onFailure). In order to make the GUI performance
more tuneable, I'll set the executor's thread pool size in the Spring
config.
When I tried unit testing some of this, the threading got in the way of
JUnit, and I haven't figured out a good alternative for this yet. A
JUnitExecutor might be a useful addition.
The other thing I'd like to be able to do, is inject a component capable of
monitoring either a single event helper, or the event manager in general.
I have some events that are cached, and only persisted to the database
when the user decides that he's finished making adjustments. If I
attempted to persist each small change the user makes, there would be too
much chatter going on and performance would suffer.
I'd like to simply attach a component that would monitor all tasks and give
the user feedback when things have updated properly. If there are any
problems, the progress bars (one per task) would turn red, and the user
could click on a specific bar to get detailed error information.
In cases where the events are not cached, I'm planning on a creating a
simple generic Task that shows success or failure dialogs when the task
completes. If I take Anthony's suggestion correctly, the *call* method is
the equivalent of Dan's *doTaskStuff*, and the *onSuccess* or
*onFailure*is the equivalent of
*doThisStuffAfter. * From the docs, it sounds like Services are (aside
from being confusingly named) reusable Tasks.
Hope this helps,
Mark
On Tue, Apr 2, 2013 at 9:25 AM, Daniel Zwolenski <zonski at gmail.com> wrote:
> Just on the topic, I've had situations where I've wanted Tasks (and
> Services) to run in my own threading model (e.g. for unit testing). So I've
> had similar wants to Mark's original request (but not directly with
> Platform.runLater, though that may also be useful).
>
> It would be nice if the Task API was really just a way of saying what I
> want done at each stage (i.e. doThisStuffBefore, doTaskStuff,
> doThisStuffAfter), then I could/should be able to call those methods
> directly myself from my own execution framework that may or may not be FX
> related or even thread related (in much the same way Runnable doesnt
> necessairly have anything to do with Threads).
>
> >From memory this wasnt (cleanly/easily) achievable because of the tight
> interdependency between Tasks and the FX threading model and property
> change events, etc.
>
> A couple of use cases:
>
> - unit or integration testing, where I want to make sure certain
> things/tasks happen in a certain sequence.
> - reusing tasks (particularly the background bit of them) outside of JFX
> eg. reuse of REST style calls in an Android, Swing, Command line, GWT,
> or
> AJAX based app (Java compiled to JScript).
>
>
>
>
>
>
>
>
>
>
>
> On Tue, Apr 2, 2013 at 10:27 AM, Richard Bair <richard.bair at oracle.com
> >wrote:
>
> > Hi Anthony, he's talking about
> > http://docs.oracle.com/javafx/2/api/javafx/concurrent/Task.html and
> > related API in the javafx.concurrent package.
> >
> > The answer is yes, the onXXX methods of Task are called on the FX thread,
> > and as such, you don't need to perform another runLater. There's a large
> > amount of documentation that should (hopefully) clearly detail which
> > threads which methods are called on (and which methods can be called from
> > any thread vs. only the FX thread). But in general on Task only the
> "call"
> > method is called on a background thread, and you may call any of the
> > updateXXX methods from the background thread but all other methods are on
> > the FX thread.
> >
> > Cheers
> > Richard
> >
> > On Apr 2, 2013, at 6:31 AM, Anthony Petrov <anthony.petrov at oracle.com>
> > wrote:
> >
> > > (Please use "Reply All" when replying to a mailing list. Thank you.)
> > >
> > > I'm not sure what Task you mean here, and how you started its execution
> > in the first place. But if I assume you've followed my advice and created
> > your own executor service and submitted your task to it, then the answer
> is
> > no. The executor service doesn't know anything about FX or its event
> > thread. I suggest to use runLater() in your onSucceeded and onFailed
> > implementations for your task if you need this code to perform some
> > GUI-related operations.
> > >
> > > --
> > > best regards,
> > > Anthony
> > >
> > > On 4/2/2013 17:23, Mark Fortner wrote:
> > >> Thanks, Anthony. The light came on after I saw Richard's reply. Are
> the
> > onSucceeded, onFailed methods of Tasks executed on the Application thread
> > or do I need to call runLater?
> > >> Mark
> > >> On Apr 2, 2013 1:18 AM, "Anthony Petrov" <anthony.petrov at oracle.com
> <mailto:
> > anthony.petrov at oracle.com>> wrote:
> > >> Platform#runLater is not a general purpose mechanism to execute
> > >> deferred tasks. Its purpose is to schedule execution of runnables
> on
> > >> the event thread in order to perform GUI-related operations. As
> > >> Richard says, the event thread is a native GUI thread. There's only
> > >> one such thread per application, hence the design of this
> machinery.
> > >> Note that running code that is unrelated to GUI on the event thread
> > >> may only make your application UI more sluggish and jerky, or even
> > >> appearing frozen sometimes.
> > >> If you need to execute general-purpose tasks asynchronously, you
> > >> have to create an executor service instance (such as a
> ForkJoinPool)
> > >> yourself and submit your runnables there.
> > >> --
> > >> best regards,
> > >> Anthony
> > >> On 4/1/2013 23:05, Mark Fortner wrote:
> > >> In the past, I've found the *Platform#runLater* method to be a
> > >> useful way
> > >> to run tasks. However, I've noticed that the code that runs my
> > >> thread is
> > >> not really configurable or accessible. For example, it would
> be
> > >> nice to be
> > >> able to specify and configure a top-level *ThreadPoolExecutor*
> > >> to handle my
> > >> tasks. Or be able to switch out *Executor* implementations.
> > >> I was wondering if there was some reason for implementing
> > >> runLater this
> > >> way, or if there are any plans to change it in the future?
> > >> Cheers,
> > >> Mark
> >
> >
>
More information about the openjfx-dev
mailing list