延迟加载卡片上的图像

时间:2013-12-10 15:37:00

标签: google-glass google-gdk

我特别关注CardScrollAdapter中的这种情况,但在将卡发布到时间线时,在LiveCard情况下也很清楚。有没有办法使用齐射或任何其他网络库来使用通用Card类加载图像?

4 个答案:

答案 0 :(得分:3)

虽然你不能直接使用Volley的NetworkImageView课程Card(因为Card管理自己的布局),你应该可以使用Volley中的其他功能来处理延迟加载你的图像。

在高级别,你可以使用这样的方法:

  1. 当您创建Card时,如果所需的图像尚未可用(在某处缓存),请最初使用占位符图像。跟踪某处Card的实例(例如,在适配器中)。
  2. 排队加载图片的请求。
  3. 检索完图像后,将图像写入应用程序的缓存目录,然后使用file: URL将其添加到卡中。
  4. 再次致电Card.toView()以重新生成卡片的观看次数并根据需要更新您的用户界面。

答案 1 :(得分: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();

    }

答案 2 :(得分:1)

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

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

我将使用Android Universal Image Loader协助进行图片下载任务。这是完成所有工作的课程:

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()中,我们找到了要加载的URL。我们询问图像加载器是否已经缓存了图像。如果有,我们找到本地文件Uri并致电card.addImage(Uri),我们就完成了。如果我们没有缓存图像,我们就不能使用正常的图像加载器displayImage()调用,因为前面描述的原因。相反,我们使用loadImage()' and if successful, ask the CardScrollView'下载文件以重新显示(不要尝试在此设置卡,即使使用final变量,也不会发生任何事情)。这将最终导致再次调用getView(),只有这次文件将被缓存。因此,图像将被添加到卡中,并且您的卡将正确显示。

还会对下载失败进行一些跟踪,以防止在下载失败时出现CardScrollView重新显示的循环。

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

CardImageLoader.init(this);

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

CardImageLoader.loadCardImage(card, url, mCardScrollView);

然后你会看到显示图像的卡片。我发现到目前为止只是警告,不要一次加载超过20张图像,否则你可能会遇到性能问题。装载150个碎玻璃,所以要小心。除此之外它一直很好。

更新:我加载了包含10多张图片的列表。我不确定是否是因为在每次图像加载后调用updateViews()或者是什么。

答案 3 :(得分:1)

“目前的XE12 GDK只支持带有本地资源和文件URI的card.addImage(Uri),这是一个额外的复杂性。所以除了上面的警告,你必须先将图像下载到文件中,然后才能添加它作为卡片图像。“

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