DevBB
DevBB

Reputation: 35

Loading images asynchronously on ListField Blackberry

How to display images fetched from url on listfield asynchronously? I am getting exception when i run the code. Here is my code. I am getting Uncaught NoClassFoundError

private Bitmap getBitmap(final String strEventCode)
{
    if(hst.containsKey(strEventCode))
        return (Bitmap) hst.get(strEventCode);
    else
    {           
        Thread t = new Thread(new Runnable() 
        {
            public void run() 
            {                       
                Bitmap bmp = HttpUtils.getBitmap(strHalfUrl+strEventCode+".jpg");
                hst.put(strEventCode, bmp);
            }
        });
        t.start();
    }
    return null; 
}

I draw image using following code using ListFieldCallBack:

class ListCallBack implements ListFieldCallback
{       
   public  void drawListRow(final ListField list, final net.rim.device.api.ui.Graphics g, final int index, final int y, final int w)
   {                  
       Event objEvent = (Event) eventData.elementAt(index);
       if(list.getSelectedIndex() == index)
       {              
           g.setColor(Color.LIGHTGRAY);
           g.fillRect(0, y, getWidth(), getHeight());            
       }
       Bitmap bmp = getBitmap(objEvent.getStrName());
       if(bmp==null)
           g.drawBitmap(0, y+5, loadingImage.getWidth(),loadingImage.getHeight(),loadingImage, 0, 0);
       else
           g.drawBitmap(0, y+5, bmp.getWidth(),bmp.getHeight(),bmp, 0, 0);

       g.setColor(Color.BLACK);
       int yPos = y + list.getRowHeight() - 1;
       g.drawLine(0, yPos, w, yPos);

       //final Bitmap b=(Bitmap)myImages.elementAt(index);
       //g.drawBitmap(0, y+5, b.getWidth(),b.getHeight(),b, 0, 0);         
   } 
   public Object get(ListField list, int index)
   { 
       return eventData.elementAt(index); 
   } 
   public int getPreferredWidth(ListField list)
   {
       return Display.getWidth();
   }
   public int indexOfList(ListField listField, String prefix, int start) 
   {
      return eventData.indexOf(prefix,start);
   }
}

Upvotes: 0

Views: 673

Answers (2)

Mister Smith
Mister Smith

Reputation: 28168

I'd change a few things:

  • In BB, there's a max number of threads you can spawn, and it is <20 I think. You are spawning a thread per image so soon or later you'll encounter a TooManyThreadsException. You should instead have a single worker thread in your screen that downloads images. You could use a consumer-producer pattern: the user, as he scrolls down, generates image download requests (producer), and the worker thread (consumer) enqueues them to be processed. You can use a LIFO structure custom made from a Vector, and wait on it while there are no requests.
  • You should provide a default image to show while the real image hasn't been downloaded yet.
  • I'm almost sure your current code is not thread safe concerning to the hst hashtable. You should ensure your consumer is thread safe. There are plenty of examples in the net about how to do this.
  • Of course the worker thread should terminate when the user changes screen. In your current code, threads remain alive and will try to update the hashtable even if the user has changed to another screen.

As an optimization, if you know in advance how many threads your app usually has (without counting the image thing), and you know the max threads limit isn't going to be exceeded, you could have a thread pool of, let say, 5 threads to download images instead of a single worker thread. When all 5 threads are busy, you'll start enqueuing requests. You can also add a max time per request mechanism to prevent a thread being busy with a failed download, so instead of timing out at 2 minutes, time out at 30s and make a second request.

Upvotes: 1

Michael Donohue
Michael Donohue

Reputation: 11876

What is HttpUtils.getBitmap()? If it is Java code written for Java-SE, then it will not work well on a BlackBerry, as BlackBerry devices only support Java-ME, which has substantially less capability than a modern Java-SE runtime.

As for the async loading, you need to pass an event back to the UI once the fetch is complete. If you are fetching many photos at once, you will also want to add some sort of batching to that event, as sending an event for each photo can overrun the event queue on the UI app.

Upvotes: 0

Related Questions