Sunday, July 20, 2008

Size Matters


Jar size is really important, people building a Hello LWUIT test MIDlet are usually surprised to find out just how big this hello world MIDlet is.
The good news is, that the MIDlet won't grow by much. The bad news is we can't fix this and reduce the size further...

When optimizing LWUIT we need to make a choice: Small size for small applications, small size (relatively) for larger applications. We chose the latter, LWUIT can support smaller applications but we consider the larger more elaborate applications as our target (widgets are a special case since they won't include a copy of LWUIT!).

The problem with the size of the hello world MIDlet is that we want to generalize as much as possible and reuse as much as possible, this helps reduce the size of a large application however a small application ends up requiring many things that aren't needed in a first glance. E.g.:

Form's have commands and menus, even if you never add any command in your application the functionality is a core LWUIT feature. So commands will be packaged in the JAR with our Form.
Menus are implemented as a list in a dialog so both of these get pulled in, with the list we have its model, default model, renderer, default renderer, animation (scrolling in List) etc...
We get transitions bundled since menus have transitions and buttons are bundled since they are used in the softbutton area... Border layout is used to arrange the forms content pane, north and south. Not to mention grid layout being used for the softbuttons container (did I mention form derives from container and component so it needs them both).
To draw everything we need to the Look and Feel, default look and feel and the UIManager. These in turn require styles, which use images and borders resources are optional...

Notice this isn't the entirety of LWUIT but it is allot so when you leverage LWUIT further your application won't grow by much.

How can you reduce the JAR size?

Make better use of resources and download them on the fly (as demonstrated by the LWUIT Demo see the downloadResources method), resource files can easily be stored in the RMS.

Use your obfuscator to track which classes get packaged and which classes do not in proguard you can add the following command line argument:
-printmapping log.txt

Which produces something like this:
com.sun.lwuit.Button -> j:
java.lang.String id -> b
[....]
com.sun.lwuit.Command -> n:
java.lang.String command -> a
int commandId -> a
[...]

Essentially allowing you to track which classes got packaged and which didn't, you can go over the list and see whether the packaged a class which it shouldn't and then try to figure out why? This also allows you to track the class mapping for every file thus you can find the sources of the biggest classes after obfuscation.

3 comments:

  1. Hi Shai, I've been having problems with Dialogs.

    My code is doing something like this:

    Dialog loadingDialog = new Dialog("Connecting...");
    loadingDialog.show();

    And then, after I connect to a socket I do something like this:

    loadingDialog.dispose();

    And it works fine, the dialog is disposed.

    But if instead of doing loadingDialog.show() I do:

    loadingDialog.show("Connecting...", "Please wait", null, null);

    Then the dialog is never disposed.

    Do you know why it happens? How can I fix this?

    ReplyDelete
  2. sir, i have downloaded the source of lwuit.. Is it possible to open the Form.java file and remove the options that are unused by my application? is it possible? so that we can reduced the size of jar know..
    i didn't started yet..please help me before proceeding it..

    ReplyDelete
  3. Guys, this is a REALLY old post ;-)
    It used to be available a couple of years ago within the LWUIT demo, possibly 1.2.
    I'm not sure where you can find that version now though, I don't have it anymore for sure.
    Anyway the code is really simple and easier yet with LWUIT4IO. Just download the res file into Storage/RMS and then load it from there since Resources.open() accepts a stream.

    ReplyDelete