In my app, I have MyAppResources
, which will mainly contain custom styles for the app. I am thinking about what is a good way to go about applying custom styles to standard widgets, such as a CellTable, along with custom styles on the layout and custom widgets?
My question:
Since MyAppResources is a singleton (it doesn't have to be, as mentioned in other posts), but CellTableResources
isn't, and CellTableResources
is a member of this instance that is an interface also extending ClientBundle
, will a proxy 'CellTableResources' be created on every MyAppResources.INSTANCE.cellTableResources().foo()
?
If so, could I create a MyAppResources.CELLTABLE_RESOURCE_INSTANCE
to get around this? Or would the creation of the proxy be negligible, even if there are plentiful calls to MyAppResources.INSTANCE.cellTableResources().#
?
Secondly, more of a discussion question: what is best practice in regards to using multiple ClientBundle
s in this case? Should I instead use CellTableResources
seperately (remove it from MyAppResources
), using GWT.create(CellTableResources.class);
in a widget that needs it (or using a singleton like I have for MyAppResources
)?
MyAppResources
:
public interface MyAppResources extends ClientBundle {
public static final MyAppResources INSTANCE = GWT.create(MyAppResources.class);
@Source("MyAppStyles.css")
public MyAppCssResource css();
public CellTableResources cellTableResources();
}
CellTableResources
:
public interface CellTableResources extends CellTable.Resources {
interface CellTableStyle extends CellTable.Style {
}
@Override
@Source({ CellTable.Style.DEFAULT_CSS, "CellTableStyles.css" })
CellTableStyle cellTableStyle();
@Source("green_light.png")
ImageResource getGreenLight();
//...
}
Thank you for reading.
Multi-part question, so I'm going to try to hit this in several parts:
What is the cost of
GWT.create()
?Most of the
GWT
class is 'magic', things that you cannot wrote for yourself in other ways, as they call on the compiler to fill in specific details for you. These are often different when running in dev mode vs compiled to JS.In the case of
GWT.create
, it turns out that this is compiled out tonew
- it is used just to create new instances. So what is the cost of a new instance versus a singleton? This depends entirely on the object being created. If there are no fields in the object, then the cost is essentially free - in fact, the compiler may choose to actually remove the constructor call, and rewrite all later methods asstatic
anyway!This is what happens in most cases -
GWT.create
should be considered to be very cheap, unless you are doing something silly like calling it within a loop that is run many times.What happens when I list a
ClientBundle
method inside anotherClientBundle
?Well, what happens when you list anything inside a
ClientBundle
?Anything that can be listed in a ClientBundle must be annotated with
@ResourceGeneratorType
, indicating how to generate that type. For example, here isImageResource
:It calls on
ImageResourceGenerator
to create images as needed. Any class described in that annotation must implementcom.google.gwt.resources.ext.ResourceGenerator
, which describes how to get ready to work, how to create necessary fields, how to initialize them, and how to finish up.So what does this look like for ClientBundle itself? Check out
com.google.gwt.resources.rg.BundleResourceGenerator
- it is a very simple class that just callsGWT.create()
on the type of the method given. So, predictable, this means that those 'child' ClientBundles are created via GWT.create, more or less the same as you might otherwise do.Okay, what does that mean in this specific case?
It turns out that ClientBundles instances don't have fields where they track newly created objects from, but instead have static members that they use instead - effectively singletons. This means that once you have called a method once, the instance it returns will be the same instance created as the next time you call it. Two different ClientBundles with the same contents will of course then keep two different copies of the objects, but it doesn't matter how many times you create a ClientBundle - its internals will always be the same.
Anything else?
Yep! Remember that you are dealing with interfaces here, not classes, so you can actually extend more than once at once!
Now, if two interfaces describe the same methods you may have problems, but if not, this can provide an advantage when generated sprited images. Each individual
ClientBundle
will draw on its own pool of images when preparing them for use - if you have aClientBundle
within aClientBundle
, they won't work together to sprite images into bigger pieces. To get that, you need to make just oneClientBundle
type. This may not matter in your particular case, but I figured it was also worth mentioning.