Custom List with lazy loading

后端 未结 2 862
予麋鹿
予麋鹿 2021-01-16 15:48

I have successfully implemented like this for lazy loading in custom list \"enter

and

2条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-16 15:58

    Assuming you start with the code I posted in this answer, and use the code you show in this question to download images from a list of URLs, then you should be able to achieve lazy image loading with the following changes:

    Create a listener interface that gets notified when downloads complete:

    public interface DownloadListener {
       // invokes if download success
       public void downloadSuccess(Bitmap bitmap);
    
       // invokes if download failed
       public void errorOccured();
    }
    

    Then, the Manager subclass that represents one list row, CustomListRow, is modified to implement this interface, and update the _thumb image when the download completes:

    public class CustomListRow extends Manager implements DownloadListener, FieldChangeListener {
    
       public void downloadSuccess(final Bitmap img) {
          _data.setThumb(img);
          // make sure bitmap is updated on the UI / main thread
          UiApplication.getUiApplication().invokeLater(new Runnable() {
             public void run() {
                _thumb.setBitmap(img);
             }
          });
       }
    
       public void errorOccured() {
           // TODO: handle error
       }
    

    Then, you'll need to add some code to create all your threads to download images in the background, and notify the DownloadListeners when the image downloads complete. You can decide where to do this. In my example, I will do this in my ListScreen class, where I instantiate the ListRander data objects and the CustomListField:

         for (int i = 0; i < numberOfItem; i++) {
            ListRander lr = new ListRander("Product Name " + i, icon);  // icon is placeholder for thumbnail image
            data.addElement(lr);
         }
         final CustomListField list = new CustomListField(data);
         add(list);
         list.setChangeListener(this);
    
         pool = new ThreadPool(3);  // 3 concurrent download threads
    
         for (int i = 0; i < numberOfItem; i++) {
            final int row = i;
    
            // create a new runnable to download the next image, and resize it:
            pool.assign(new Runnable() {
               public void run() {
                     try {            
                        String text=object[row].getJSONArray("UrlArray").getString(0).toString();
                        EncodedImage encodedImg = JPEGEncodedImage.encode(connectServerForImage(text), quality);    //connectserverForImage load Images from server                     
                        EncodedImage logoThumbnail = sizeImage(encodedImg, Display.getWidth(), Display.getHeight()-100);
                        list.getRow(row).downloadSuccess(logoThumbnail.getBitmap());
                     } catch (Exception e) {
                        e.printStackTrace();
                        list.getRow(row).errorOccured();
                     }
                  }
               }
            });
         }
    

    You could do this in the ListScreen constructor, or whenever you have your object[] array of URLs.

    You'll need to add a new method to CustomListField:

    public CustomListRow getRow(int row) {
        return (CustomListRow)getField(row);
    }
    

    The code above also needs a member variable added (in ListScreen) to create a thread pool:

    private ThreadPool pool;
    

    This thread pool implementation is based on this tutorial here, with very minor modifications, simply to change ArrayList (not available on BlackBerry Java) to Vector ... and removing the calls to Thread#destroy(). You'll need to copy that tutorial's ThreadPool, WorkerThread, and Done classes to your project. The above example I show creates a thread pool of 3 threads. On a single CPU smartphone, 2 or 3 threads is probably fine for your needs. Read more here if you want to get the perfect number of threads for your application.

    Note: if possible, you can usually improve performance if you download images that are exactly the right size for your application, instead of burdening the network with larger images, and then resizing them inside your app. However, I realize that this depends on having some control over the images' web server, which you may not have. Just a thought for later optimization.

提交回复
热议问题