Andy Smith
Andy Smith

Reputation: 3345

TreeViewer lazy loading of icon only

I have a TreeViewer, it displays a list of items. My constrains are as follows:

When I do a getChildren() for by TreeViewer items I read in each XML file and generate the Object[] array from there. Up until recently this has been acceptable but it is not any more. The normal number of XML files was 10, it is now 500.

I need to improve performance. However, for a variety of reasons such as compatablity the following options are not possible

From my tests a reasonable performance is found when just getting a directory listing of the XML files and using this for the labels. The label name is the most important aspect and whilst the image type is useful its presence is not immediately required.

These requirements and constrains have lead me to the following solution:

  1. Initial getChilren() scans the directory of XML files and returns a list of labels with a 'missing' type image. (getImage() = missingImage)
  2. getChilren() then starts up a background Job which reads in the XML files and attains the type.
  3. Each Object[] has a cacheImage() method which loads in the type image (so getImage() == properIcon now). This is called by the Job.
  4. Job then iterates over each item in the tree and calls an update(), for each item

I have implemented this and the performance leaves something to be desired. Additionally, because we have so many calls to Display.getDefault().asyncExec to do the update, the GUI (whilst still be responsive) will take time to respond to user interactions (whilst not actually locking). Are there any ways I can improve this?

The following has been considered/tried:

Upvotes: 0

Views: 753

Answers (4)

hudsonb
hudsonb

Reputation: 2304

I would suggest loading/creating several images at once in the background thread (from what you said it sounds like you could do at least 10 w/o a performance issue). So your thread would look something like:

// Load/Create some number of images...

Display.asyncExcec(new Runnable() {
    public void run() {
        getTreeViewer().setRedraw(false);
        // Loop and call update on each node you loaded the image for
        getTreeViewer().setRedraw(true);
    }
});

Upvotes: 0

the.duckman
the.duckman

Reputation: 6406

Try lowering the priority of your background thread by calling

this.setPriority(this.getPriority()-1);

in your Thread.

500 calls to asyncExec should not make the GUI unresponsive, if they don't do more than setting an Image in a TreeItem. To ensure, that your calls to TreeViewer.update are cheap, call

TreeViewer.setUseHashlookup(true)

which enables efficient mapping of elements to TreeItems.

Upvotes: 1

Konstantin Komissarchik
Konstantin Komissarchik

Reputation: 29139

I would recommend the following optimization strategies (in order)...

  1. Batch update calls. That is, have a list into which you deposit content objects whose image has been calculated. When the list size arrives at a certain threshold (or you run out of objects), kick off an update of all the objects presently in the list. Make sure to copy the contents of the list first and clear the list so that the caching thread can keep accumulating. Play around with the threshold parameter and you will likely get the perf you are after by reducing the number of asyncExec calls.

  2. If #1 is not sufficient by itself (unlikely), you may also want to consider optimizing around the viewable region. Tree class has api around tracking which items are visible and you can listen for scroll events. The idea here is to prioritize image calculation for items that are visible and to call update on items only after they've become visible.

Upvotes: 0

Zoltán Ujhelyi
Zoltán Ujhelyi

Reputation: 13858

Wouldn't it help, if you load all images to an ImageRegistry in a background job (possibly using the XML), and then simply adding the images from this registry?

Upvotes: 0

Related Questions