Custom List with lazy loading

后端 未结 2 861
予麋鹿
予麋鹿 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.

    0 讨论(0)
  • 2021-01-16 15:59

    I am sure that I seen a good answer to this question on my travels, but can't find it now. I do recommend reviewing the BB forums here: http://supportforums.blackberry.com/t5/Java-Development/bd-p/java_dev as there are similar questions there.

    For now, just the highlights of what you need to do:

    1. Create an image downloading runnable to process the download - you have pretty much already done this in your previous code.
    2. Use the Observer pattern (search the internet for this), so that the BitmapField is the Observer for the completion of your image downloading. So when the image has been downloaded, the Runnable invokes the observer, which can then update the Bitmap.
    3. Use a Thread pool with a limited number of Threads (I would say 3), so that you do not start a whole load of image downloads at the same time. Search the internet for information on Thread Pool for help implementing this. You had not done this step in your previous example, and you can get away with running all the downloads, but I expect at some stage that this will fail.

    Put these together and you have your solution. Not trivial I know. Good luck.

    0 讨论(0)
提交回复
热议问题