4

我特别关注在 a 中执行此CardScrollAdapter操作,但在将卡片发布到时间线时,了解 LiveCard 情况也很好。有没有办法使用 volley 或任何其他网络库来使用泛型Card类加载图像?

4

4 回答 4

3

虽然您不能NetworkImageView直接将 Volley 的类与 a 一起使用Card(因为它Card管理自己的布局),但您应该能够使用 Volley 中的其他功能来处理延迟加载图像。

在高层次上,您可以使用如下方法:

  1. 当您创建您的Card时,如果所需的图像尚不可用(缓存在某处),则让它最初使用占位符图像。跟踪Card某处的实例(例如在适配器中)。
  2. 将加载图像的请求排入队列。
  3. 检索到图像后,将图像写入应用程序的缓存目录并使用file:URL 将其添加到卡中。
  4. 再次调用Card.toView()以重新生成卡片的视图并根据需要更新您的 UI。
于 2013-12-10T19:22:21.243 回答
2

“更新:我在加载包含 10 多个图像的列表时变慢了。我不确定这是由于在每次图像加载后调用 updateViews() 还是什么。”

确保您的 CardScrollAdapter getView() 方法不会尝试在每次调用时加载图像。

例如:

   @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if ( getCards() == null ) return null;

        MyCard card = getCards().get(position);

        if (! card.isImageLoaded()) {
                    CardImageLoader.loadCardImage(...);     
        }

           return card.toView();

    }
于 2014-03-21T20:32:53.323 回答
1

好的,有办法做到这一点,但它有点令人费解。诀窍是你不能getView()在适配器中调度异步图像加载任务,就像你通常在 android 中那样。如果你尝试,你会发现当你准备好加载图像时,ImageView返回的将被 GC 处理。card.toView()似乎是 GDK 中的一个错误,或者可能是它的设计方式,我不确定。

当前的 XE12 GDK 仅支持card.addImage(Uri)本地资源和文件 URI 存在额外的复杂性。因此,除了上述警告之外,您必须先将图像下载到文件中,然后才能将其添加为卡片图像。

我将使用Android 通用图像加载器来协助完成图像下载任务。这是完成这一切的课程:

public class CardImageLoader {

    private static final String TAG = CardImageLoader.class.getSimpleName(); 
    private static final boolean DEBUG = false;

    private static final int MAX_IMAGE_LOAD_RETRIES = 3;
    private static Map<String, Integer> mLoadFailures = new ConcurrentHashMap<String, Integer>();

    public static void init(Context context) {
        File cacheDir = StorageUtils.getCacheDirectory(context);
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .cacheOnDisc(true)
                .build();
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .discCache(new UnlimitedDiscCache(cacheDir))
                .defaultDisplayImageOptions(options)
                .build();
        ImageLoader.getInstance().init(config);
    }

    public static void loadCardImage(final Card card, final String imageUri, final CardScrollView cardScrollView) {
        card.setImageLayout(Card.ImageLayout.FULL);
        int failures = mLoadFailures.containsKey(imageUri) ? mLoadFailures.get(imageUri) : 0;
        if (failures > MAX_IMAGE_LOAD_RETRIES) {
            if (DEBUG) Log.i(TAG, "Exceeded max retries on imageUri=" + imageUri);
            return;
        }
        File file = ImageLoader.getInstance().getDiscCache().get(imageUri);
        if (file != null && file.exists() && file.length() > 0) {
            Uri uri = Uri.fromFile(file);
            card.addImage(uri);
        }
        else {
            ImageLoader.getInstance().loadImage(imageUri, new ImageLoadingListener() {
                @Override
                public void onLoadingStarted(String imageUri, View view) {
                    if (DEBUG) Log.i(TAG, "onLoadingStarted");
                }

                @Override
                public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                    if (DEBUG) Log.i(TAG, "onLoadingFailed");
                    int failures = mLoadFailures.containsKey(imageUri) ? mLoadFailures.get(imageUri) : 0;
                    mLoadFailures.put(imageUri, ++failures);
                }

                @Override
                public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                    File file = ImageLoader.getInstance().getDiscCache().get(imageUri);
                    if (DEBUG) Log.i(TAG, "onLoadingComplete uri=" + imageUri + " file=" + file
                            + " len=" + (file == null ? 0 : file.length()));
                    if (file != null && file.exists() && file.length() > 0) {
                        if (DEBUG) Log.i(TAG, "onLoadingComplete scheduling update of scroll views");
                        if (cardScrollView != null)
                            cardScrollView.updateViews(true);
                    }
                }

                @Override
                public void onLoadingCancelled(String imageUri, View view) {
                    if (DEBUG) Log.i(TAG, "onLoadingCancelled");
                }
            });
        }
    }
}

这是它的工作原理。在getView()adapter中,我们找到我们要加载的URL。我们询问图像加载器是否已经缓存了图像。如果有,我们找到本地文件 Uri 并调用card.addImage(Uri),我们就完成了。如果我们没有缓存图像,我们就不能使用正常的图像加载器displayImage()调用,原因如上所述。相反,我们使用loadImage()' and if successful, ask theCardScrollView' 下载文件以重新显示自身(不要尝试在此处设置卡片,即使使用final变量,也不会发生任何事情)。这最终会导致getView()再次调用,只有这一次文件会被缓存。因此,图像将被添加到卡片中,您的卡片将正确显示。

还有一些失败下载的跟踪,以防止失败下载时CardScrollView重新显示的循环。

你如何使用它?挺容易。首先,您onCreate()需要使用以下行初始化图像加载器:

CardImageLoader.init(this);

其次,在您的适配器getView()方法中,当您想在卡片中加载图像时,您调用此方法:

CardImageLoader.loadCardImage(card, url, mCardScrollView);

然后,您将看到带有图像的卡片。到目前为止我发现的唯一警告是,不要一次加载超过 20 张左右的图像,否则您可能会开始遇到性能问题。装载 150 个碎玻璃,所以要小心。除此之外,它工作正常。

更新:我在加载包含 10 多个图像的列表时会变慢。我不确定这是由于updateViews()在每次图像加载后调用还是什么。

于 2014-01-21T15:00:14.073 回答
1

“当前的 XE12 GDK 仅支持具有本地资源和文件 URI 的 card.addImage(Uri) 存在额外的复杂性。因此,除了上述警告之外,您必须先将图像下载到文件中,然后才能将其添加为卡片图像。”

看起来 XE16+ 现在支持 card.addImage(bitmap) 因此可能不再需要使用文件作为临时缓存。

于 2014-05-21T17:21:41.817 回答