Akintayo Olusegun
Akintayo Olusegun

Reputation: 917

LWUIT: Load images in background thread

I have a list that contains about 20 image URLs and some other things.

I want to display the other things (description) and allow the user to interact with the app while I load the 20 images.

What I noticed is that no matter what I tried, I can't interact with the form until the images finished loading even though I am doing the loading in another thread.

This is my solution I am using now.

private Container createServerItems() throws Exception {
    Container list = new Container(new BoxLayout(BoxLayout.Y_AXIS));

    final int size = mediaList.size();

    final Button buttons[] = new Button[size];

    System.out.println("In here: " + size);
    for (int i = 0; i < size; i++) {
        Container mainContainer = new Container(new BorderLayout());
        Media m = new Media();
        m.fromJSONString(mediaList.elementAt(i).toString());

        buttons[i] = new Button("please wait");

        final int whichButton = i;
        Display.getInstance().callSerially(new Runnable() {

            public void run() {
                try {
                    System.out.println(MStrings.replaceAll(m.getImgURL(), "\"", ""));
                    final StreamConnection streamConnection = (StreamConnection) Connector.open(MStrings.replaceAll(m.getImgURL(), "\"", ""));                        
                    Image image = Image.createImage(streamConnection.openInputStream());
                    streamConnection.close();

                    buttons[whichButton].setText("");
                    buttons[whichButton].setIcon(image.scaled(32, 32));

                } catch (Exception e) {
                }
            }
        });
        TextArea t = new TextArea(m.getDesc());
        t.setEditable(false);
        t.setFocusable(false);
        t.setGrowByContent(true);

        mainContainer.addComponent(BorderLayout.WEST, buttons[i]);
        mainContainer.addComponent(BorderLayout.CENTER, t);

        list.addComponent(mainContainer);
    }
    return list;
}

Upvotes: 2

Views: 1607

Answers (2)

Vimal
Vimal

Reputation: 1266

APPROACH I : LWUIT 1.5 has a powerful LWUIT4IO library to address your problem.

An excerpt from Shai's Blog link

A feature in LWUIT4IO to which I didn't give enough spotlight is the cache map, its effectively a lean hashtable which stores its data using weak/soft references (depending on the platform) and falls back to storage when not enough memory is available. Its a great way to cache data without going overboard. One of the cool things about it is the fact that we use it seamlessly for our storage abstraction (which hides RMS or equivalent services) in effect providing faster access to RMS storage which is often slow on devices.

Another useful link is here

The idea is to delegate the Network IO functionality to a singleton to avoid any UI deadlocks, like the one you are facing.

A very good video demo here by vprise, explains how to bind GUI functionality to your netbeans. In this video at around 7:00 mins it explains the use of ImageDownloadService class which binds the component to its thumbnail url which will seamlessly fetch from the network and populate the Image.

APPROACH II: Difficult one of create custom logic

  1. Create a singleton that will interface with the network to fetch the data
  2. Use a queue to handle the sequential image download services
  3. Create a new thread for this singleton and wait on the queue.
  4. With each image download service bind a listener with the invoking component so that it easier to update the right component.

Upvotes: 2

Thomas
Thomas

Reputation: 5094

According to the lwuit spec, callSerially() executes on the Event Dispatch Thread, which means that it will block other events until it completes. You need to move your code to load the image outside of that method and keep only the setText and setIcon calls in callSerially().

Upvotes: 1

Related Questions