FX Application startup & threads [message #1386051] |
Fri, 13 June 2014 08:37 |
Sun Volland Messages: 29 Registered: September 2010 |
Junior Member |
|
|
Hi,
We noticed that all the E4 FX application startup (more precisely, the application model initialization) happens in the FX event thread : model assembling, processor & addons executions, etc.
During this process, we wanted to keep a login dialog visible and alive (i.e. showing a progress indicator), so we modified the E4Application.jfxStart() method to do all this in another thread, and finally just run the workbench.createAndRunUI() in the FX thread.
This works fine for us and has the following advantages :
- the FX thread can continue UI rendering during the startup phase (i.e. our login dialog can continue show progress information)
- In the case custom addons/processors are long to execute (e.g. requiring remote services, etc.), this allows to follow progress on a UI
- when closing the "progress UI" on the applicationRunning event, main UI shows up quasi instantly.
What changes is that (may not be exhaustive) addons, processors and lifecycle methods @processRemovals and @processAdditions do no more run on the UI thread, but we guess this is not really a problem as no rendering operation should performed there.
As said this works fine for us, does one see any problem this could lead to, or use cases this could break ?
If not, couldn't this be an enhancement ?
Our modified E4Application.jfxStart() method below :
@Override
protected void jfxStart(IApplicationContext applicationContext, Application jfxApplication, Stage primaryStage) {
Runnable startRunnable = new Runnable() {
@Override
public void run() {
workbench = createE4Workbench(applicationContext, jfxApplication, primaryStage);
if (workbench != null) {
instanceLocation = (Location) workbench.getContext().get(E4Workbench.INSTANCE_LOCATION);
try {
if (!checkInstanceLocation(instanceLocation)) {
return;
}
workbenchContext = workbench.getContext();
// Create and run the UI (if any)
UISynchronize uiSync = workbench.getContext().get(UISynchronize.class);
uiSync.syncExec(new Runnable() {
@Override
public void run() {
workbench.createAndRunUI(workbench.getApplication());
}
});
} finally {
applicationContext.applicationRunning();
}
}
}
};
Thread t = new Thread(startRunnable);
t.start();
}
Sun
|
|
|
Re: FX Application startup & threads [message #1386056 is a reply to message #1386051] |
Fri, 13 June 2014 09:04 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
Sounds reasonable - file a bug and if possible provide a gerrit-review
and we can merge that in.
Maybe we should add the possibility for developers to define how the
start up process should be handled?
The only change i would make is to call
"applicationContext.applicationRunning(); " in the UI-Thread. The reason
for that is that people who use the Eclipse-Splash (only win32 users can
do that today!) need this method to be called on the launcher thread or
the splash will not close.
Tom
On 13.06.14 10:37, Sun Volland wrote:
> Hi,
>
> We noticed that all the E4 FX application startup (more precisely, the
> application model initialization) happens in the FX event thread : model
> assembling, processor & addons executions, etc.
> During this process, we wanted to keep a login dialog visible and alive
> (i.e. showing a progress indicator), so we modified the
> E4Application.jfxStart() method to do all this in another thread, and
> finally just run the workbench.createAndRunUI() in the FX thread.
>
> This works fine for us and has the following advantages :
> - the FX thread can continue UI rendering during the startup phase (i.e.
> our login dialog can continue show progress information)
> - In the case custom addons/processors are long to execute (e.g.
> requiring remote services, etc.), this allows to follow progress on a UI
> - when closing the "progress UI" on the applicationRunning event, main
> UI shows up quasi instantly.
>
> What changes is that (may not be exhaustive) addons, processors and
> lifecycle methods @processRemovals and @processAdditions do no more run
> on the UI thread, but we guess this is not really a problem as no
> rendering operation should performed there.
>
> As said this works fine for us, does one see any problem this could lead
> to, or use cases this could break ? If not, couldn't this be an
> enhancement ?
>
> Our modified E4Application.jfxStart() method below :
>
>
> @Override
> protected void jfxStart(IApplicationContext applicationContext,
> Application jfxApplication, Stage primaryStage) {
> Runnable startRunnable = new Runnable() {
> @Override
> public void run() {
> workbench = createE4Workbench(applicationContext,
> jfxApplication, primaryStage);
> if (workbench != null) {
> instanceLocation = (Location)
> workbench.getContext().get(E4Workbench.INSTANCE_LOCATION);
>
> try {
> if (!checkInstanceLocation(instanceLocation)) {
> return;
> }
>
> workbenchContext = workbench.getContext();
>
> // Create and run the UI (if any)
> UISynchronize uiSync =
> workbench.getContext().get(UISynchronize.class);
> uiSync.syncExec(new Runnable() {
> @Override
> public void run() {
>
> workbench.createAndRunUI(workbench.getApplication());
> }
> });
>
> } finally {
> applicationContext.applicationRunning();
> }
> }
> }
> };
> Thread t = new Thread(startRunnable);
> t.start();
> }
>
>
>
> Sun
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Re: FX Application startup & threads [message #1386572 is a reply to message #1386563] |
Wed, 18 June 2014 09:54 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
Hi,
I think the solution must be different - I'm not sure we could get that
from upstream but we could implement it on our ScopedObjectFactory
ourselves for now.
The really important code is at - InjectorImpl.invokeUsingClass() we
could copy that code to our own factory and read the meta informations
about invocation.
I'll try to prototype this later on to see if it is possible, maybe we
could convince upstream that they modify their code a bit so that adding
a method
public MethodRequestor invokeUsingClass(Object userObject, Class<?>
currentClass, Class<? extends Annotation> qualifier, Object
defaultValue, PrimaryObjectSupplier objectSupplier,
PrimaryObjectSupplier tempSupplier, boolean throwUnresolved) {
// ...
}
so that we don't have to duplicate stuff - naturally we are with that
outside the API scope and I don't know if we have access to all APIs we
need without residing to reflection.
Tom
On 18.06.14 11:27, Christoph Keimel wrote:
> Hi Tom,
>
> I had a look at extending CIF the way you proposed below, because that
> would also elegantly solve this issue. I was thinking about extending
> the IInjector with the proposed functionality. This seems to be rather
> difficult at the moment, since the IInjector used in CIF is implemented
> as a Singleton.
>
> final private static IInjector injector = InjectorFactory.getDefault();
> I created a proposal to publish IInjector as an OSGi service upstream:
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=437657
>
> This would enable us to create an extended service, no? Or am I missing
> something in my train of thought?
>
> Smile,
> Christoph
>
> Thomas Schindl wrote on Tue, 17 June 2014 13:31
>> Generally speaking I'd like to have a possibility when stuff is invoked
>> via CIF.invoke to mark that the method has to called on the UI-Thread in
>> a syny/async fashion.
>>
>> I dream of something like this:
>>
>> @Execute
>> @UISync
>> public String bla() {
>> }
>>
>> and
>>
>> @Execute
>> @UIAsync
>> public Future<String> bla() {
>> }
>>
>> Tom
>
|
|
|
|
|
|
Re: FX Application startup &amp;amp;amp; threads [message #1693763 is a reply to message #1693761] |
Tue, 28 April 2015 08:53 |
Bastien Bart Messages: 21 Registered: May 2014 |
Junior Member |
|
|
I used it to handle my login stage
@PostContextCreate
boolean login(IEventBroker broker, UISynchronize sync, IEclipseContext pEclipseContext) {
boolean loginState;
BlockCondition<Boolean> blockCondition = new BlockCondition<>();
splashService = new LoginStage();
splashService.open(pEclipseContext);
splashService.loggedProperty().addListener(change -> {
if(splashService.isLogged()) {
blockCondition.release(true);
}
} );
loginState = sync.block(blockCondition);
broker.subscribe(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE, event -> splashService.close());
broker.subscribe(ConstantsUi.UIEvents.START_STEP, event -> {
if(event.containsProperty("org.eclipse.e4.data")) {
splashService.setMessage((String) event.getProperty("org.eclipse.e4.data"));
}
} );
// return true;
splashService.open(eclipseContext);
}
There is an other way?
Thanks a lot
[Updated on: Tue, 28 April 2015 08:55] Report message to a moderator
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.06960 seconds