1

I'm developing an application consisting of 3 modules.

The users can start a web chat (implemented as a widget) and then navigate through the modules. I would like the web chat widget to be kept during the navigation.

I've added a static field in the widget containing the current instance, but it is only persisted while I remain in the same module. If I change module the widget is re-created by scratch.

Is there a way to define an object with application scope?

algiogia
  • 936
  • 2
  • 14
  • 40

2 Answers2

0

A better solution (than keeping global state) would be to use Dependency Injection and inject your widget to all relevant views.

Using gin it'd look like this:

@Singleton
public class CommonWidget {
}

public class View1 {
    @Inject
    public View1(CommonWidget widget) {
    }
}

public class View2 {
    @Inject
    public View2(CommonWidget widget) {
    }
}

Now, widget in View1 and View2 point to the same widget. The problem is that you have to be careful when using this widget - remember that you can only add a widget once to the DOM, so before adding it in View2, you have to remove it from View1.

I think that instead sharing the widget this way, you should either share the messages between two chat widgets or better yet, move the chat widget "above" the views (either literally or figuratively), so that there's only one instance.

Of course, there are more steps to setting up gin, but you can read about them in the docs.

Igor Klimer
  • 15,321
  • 3
  • 47
  • 57
  • There is already only ONE instance of the widget. I'm maintaining a static reference in the Widget. If 'null' I create a new one, otherwise I return the existing instance. The problem is that static fields' scope seems to be the module, not the application. – algiogia Nov 17 '14 at 14:22
  • 1
    @algiogia in the same way that this isn't how Java works (excluding classloader trickier), that isn't how Java works when running in GWT. You have to behave as if there is one GWT-based classloader ;). – Colin Alworth Nov 17 '14 at 19:15
  • Sorry @ColinAlworth but I don't think I understand your comment. In Java, static fields are available to the entire application (someone even suggests to the JVM http://stackoverflow.com/a/797989/2442991). So I would expect GWT to do (almost) the same. – algiogia Nov 18 '14 at 09:21
  • 1
    @algiogia I'm saying that for a given compiled GWT module, it behaves like the JVM - a static instance is one instance, and all objects, no matter where they were defined (in that module) can see it. But, just like two different running JVMs can't see each other's static members, two different running (i.e. not compiled together) modules can't see each other's instances. You can write some code to make them communicate, but switching to a new JVM (restarting the app, or starting a second app) means old objects aren't retained. Note that this is different than one module inheriting another. – Colin Alworth Nov 20 '14 at 17:54
0

You can create any widget in your entry point class (#onModuleLoad), and then reference/call this widget from any activity that needs it. However, I would only recommend this solution in two cases:

  1. A widget is a container for the entire application or part of the application (e.g. top menu, main panel) that is always visible on a screen, so you don't add/remove it from UI - you simply call it to change its state.

  2. A widget is a popup panel or similar (e.g. confirm dialog, error notification, etc.), so reusing it in different activities/views does not cause any problems.

You may want to take a look at Activities and Places design pattern. It supports most typical navigation scenarios, where you move from one Activity/View to another within the same app (container) widget.

UPDATE:

This is a quote from GWT docs about the use of multiple modules:

If you have multiple GWT modules in your application, there are two ways to approach loading them.

  1. Compile each module separately and include each module with a separate tag in your HTML host page.
  2. Create a top level module XML definition that includes all the modules you want to include. Compile the top level module to create a single set of JavaScript output.

The first approach may seem the easiest and most obvious. However, the second approach will lead to much better end-user performance. The problem with loading multiple modules is that each module has to be downloaded separately by the end-user's browser. In addition, each module will contain redundant copies of GWT library code and could possibly conflict with each other during event handling. The second approach is strongly recommended.

Andrei Volgin
  • 40,755
  • 6
  • 49
  • 58
  • I have 3 different entry points and need to keep the widget even when navigating from one entry point to the other. – algiogia Nov 18 '14 at 11:42
  • When you navigate to another entry point, it's a totally new page for a browser - the DOM is cleared and all of your widgets, data, etc. is lost. – Andrei Volgin Nov 18 '14 at 17:07
  • @AndreiVolgin, your comment is incorrect. There can be many entry points, when many modules are loaded. Consider a case, when you have a parent module and a child module. If these modules have entry points - both of them will be executed, without cleaning the DOM. – Andrew Nov 18 '14 at 22:06
  • @Andrew - You _can_ do it, but it's a bad idea. Most GWT apps are organized as a single module with a single entry point, which inherits other modules as necessary. See http://stackoverflow.com/questions/3292671/multiple-entry-points-in-gwt. I also updated my response with a quote from GWT docs. – Andrei Volgin Nov 19 '14 at 06:19
  • Andrei, in my comment I was referencig the 2nd approach, quoted in your answer. I do not see, why it would be a bad idea. – Andrew Nov 19 '14 at 11:55
  • The second approach is one module with one entry point. It's a good idea. All inherited modules do not have entry points - their source code is compiled into a single "app". – Andrei Volgin Nov 19 '14 at 15:05