我特别关注在 a 中执行此CardScrollAdapter
操作,但在将卡片发布到时间线时,了解 LiveCard 情况也很好。有没有办法使用 volley 或任何其他网络库来使用泛型Card
类加载图像?
4 回答
虽然您不能NetworkImageView
直接将 Volley 的类与 a 一起使用Card
(因为它Card
管理自己的布局),但您应该能够使用 Volley 中的其他功能来处理延迟加载图像。
在高层次上,您可以使用如下方法:
- 当您创建您的
Card
时,如果所需的图像尚不可用(缓存在某处),则让它最初使用占位符图像。跟踪Card
某处的实例(例如在适配器中)。 - 将加载图像的请求排入队列。
- 检索到图像后,将图像写入应用程序的缓存目录并使用
file:
URL 将其添加到卡中。 - 再次调用
Card.toView()
以重新生成卡片的视图并根据需要更新您的 UI。
“更新:我在加载包含 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();
}
好的,有办法做到这一点,但它有点令人费解。诀窍是你不能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 the
CardScrollView' 下载文件以重新显示自身(不要尝试在此处设置卡片,即使使用final
变量,也不会发生任何事情)。这最终会导致getView()
再次调用,只有这一次文件会被缓存。因此,图像将被添加到卡片中,您的卡片将正确显示。
还有一些失败下载的跟踪,以防止失败下载时CardScrollView
重新显示的循环。
你如何使用它?挺容易。首先,您onCreate()
需要使用以下行初始化图像加载器:
CardImageLoader.init(this);
其次,在您的适配器getView()
方法中,当您想在卡片中加载图像时,您调用此方法:
CardImageLoader.loadCardImage(card, url, mCardScrollView);
然后,您将看到带有图像的卡片。到目前为止我发现的唯一警告是,不要一次加载超过 20 张左右的图像,否则您可能会开始遇到性能问题。装载 150 个碎玻璃,所以要小心。除此之外,它工作正常。
更新:我在加载包含 10 多个图像的列表时会变慢。我不确定这是由于updateViews()
在每次图像加载后调用还是什么。
“当前的 XE12 GDK 仅支持具有本地资源和文件 URI 的 card.addImage(Uri) 存在额外的复杂性。因此,除了上述警告之外,您必须先将图像下载到文件中,然后才能将其添加为卡片图像。”
看起来 XE16+ 现在支持 card.addImage(bitmap) 因此可能不再需要使用文件作为临时缓存。