1

我已经成功实现了这样的自定义列表中的延迟加载 在此处输入图像描述

我为此使用的代码在这里:Blackberry 中的带有图像的自定义列表 在链接的问题中,我定位了心脏图标的 y 坐标,并解决了链接问题的问题。

 if (logoThumbnailImage != null
     && logoThumbnailImage.length > index
     && logoThumbnailImage[index] != null) {

       EncodedImage img = logoThumbnailImage[index];
       graphics.drawImage(0, y + 10, Display.getWidth(),
                          Display.getHeight() - 100, img, 0, 0, 0);
       graphics.drawImage(300,
                          y+400,
                          heart.getWidth(), heart.getHeight(), heart,
                          0, 0, 0);

现在我想为两者处理点击事件;也就是说,对于列表行单击和心脏单击

为此,我在这里看到了@Nate 写的帖子自定义列表字段点击事件。但是在该代码中,图像不是从服务器加载的,它们是静态图像。我想用我的代码实现@Nate 的代码(即延迟加载)。

如果您有任何想法,请建议我该怎么做。提前致谢

4

2 回答 2

2

假设您从我在此答案中发布的代码开始,并使用您在此问题中显示的代码从 URL 列表中下载图像,那么您应该能够通过以下更改实现延迟图像加载:

创建一个在下载完成时收到通知的侦听器接口

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

   // invokes if download failed
   public void errorOccured();
}

然后,将代表一个列表行的 Manager 子类CustomListRow修改为实现此接口,并_thumb在下载完成时更新图像:

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
   }

然后,您需要添加一些代码来创建所有线程以在后台下载图像,并DownloadListeners在图像下载完成时通知您。您可以决定在哪里执行此操作。在我的示例中,我将在我的ListScreen类中执行此操作,在其中实例化ListRander数据对象和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();
                 }
              }
           }
        });
     }

您可以在ListScreen构造函数中执行此操作,或者在您拥有object[]URL 数组时执行此操作。

您需要添加一个新方法CustomListField

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

上面的代码还需要添加一个成员变量(in ListScreen)来创建线程池:

private ThreadPool pool;

此线程池实现基于此处的本教程,进行了非常小的修改,只需将ArrayList(在 BlackBerry Java 上不可用)更改为Vector... 并删除对Thread#destroy(). 您需要将该教程的 、 和 类复制ThreadPoolWorkerThreadDone的项目中。我展示的上述示例创建了一个包含 3 个线程的线程池。在单 CPU 智能手机上,2 或 3 个线程可能足以满足您的需求。 如果您想为您的应用程序获得完美数量的线程,请在此处阅读更多信息。

注意:如果可能的话,如果您下载的图片大小正好适合您的应用程序,通常可以提高性能,而不是让网络负担更大的图片,然后在您的应用程序中调整它们的大小。但是,我意识到这取决于对图像的网络服务器进行一些控制,而您可能没有。只是以后优化的想法。

于 2013-10-16T07:13:11.233 回答
1

我确信我在旅途中看到了这个问题的一个很好的答案,但现在找不到了。我建议在这里查看 BB 论坛:http: //supportforums.blackberry.com/t5/Java-Development/bd-p/java_dev 因为那里有类似的问题。

现在,只是您需要做的重点:

  1. 创建一个可运行的图像下载来处理下载 - 您已经在之前的代码中完成了这项工作。
  2. 使用观察者模式(在互联网上搜索),以便 BitmapField 是完成图像下载的观察者。因此,当图像下载完成后,Runnable 会调用观察者,然后观察者可以更新位图。
  3. 使用线程数量有限的线程池(我会说 3 个),这样您就不会同时开始大量的图像下载。在 Internet 上搜索有关线程池的信息,以帮助实现这一点。您在前面的示例中没有执行此步骤,您可以运行所有下载,但我预计在某个阶段这会失败。

把这些放在一起,你就有了解决方案。我知道这不是微不足道的。祝你好运。

于 2013-10-14T09:54:39.807 回答