安卓列表预缓存图片的最佳实践是什么?

3

目前我即使在用户未滚动查看时也加载图像,这样当用户滚动到图片时,图片将从Picasso缓存中快速加载,这是在列表承包商上实现的。

private void createImageCatch(ArrayList<Article> items) {
    for (int i = 0; i < items.size(); i++) {
            Article article = (Article) items.get(i);
            if (article.getImageUrl() != null
                    && article.getImageUrl().length() > 0)
                Picasso.with(mContext).load(article.getImageUrl())
                        .fetch();
    }
}

这个做法很完美,即使用户快速滚动页面,图片也已经准备好了。但是,这是最好的方法吗?

改进更新-添加了静态布尔变量,以确保只调用此方法一次。如果图片是在服务器端添加的,那么在滚动时加载少量图片并不是什么大问题,因为大部分图片已经被缓存了。


取决于ImageView的大小和ListView的项数。 - Volodymyr Kulyk
我认为这不是正确的方式,预提取尚未需要的数据实在是有些过度杀伤力了。 - Enzokie
小图像,大约30个。我也不确定这是否是最好的方法,这就是为什么我在问的原因。我想避免即使是很短的时间也出现空白图像。 - Jesus Dimrix
对于用户来说,短时间内出现空白图像并不是什么大问题,此外您可以使用占位图像。 - Enzokie
这是一个非常庞大的应用程序,我希望它尽可能地流畅... - Jesus Dimrix
2个回答

3
你考虑过使用Volley库吗?它有一个特殊的ImageView,可以为你下载和缓存图片。
将XML中的ImageView替换为以下内容:
<com.android.volley.toolbox.NetworkImageView
    android:id="@+id/photo"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentTop="true"
    android:layout_marginRight="6dip"
 />

使用以下代码加载您的图片:

NetworkImageView photo = (NetworkImageView)view.findViewById(R.id.photo);
photo.setImageUrl("http://someurl.com/image.png", mImageLoader);

你需要设置你的ImageLoader,所以创建一些字段:
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;

onCreate中初始化它们:

mRequestQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
    private final LruCache<String, Bitmap> mCache = new LruCache<String, Bitmap>(10);
    public void putBitmap(String url, Bitmap bitmap) {
        mCache.put(url, bitmap);
    }
    public Bitmap getBitmap(String url) {
        return mCache.get(url);
    }
});

来源:为NetworkImageView设置Android Google Volley ImageLoader


但是 Picasso 也可以为我完成这个任务,那么有什么不同呢?我也考虑过 Glide,但如果我现在的理解是正确的话,结果应该是一样的。我在考虑也许只对当前位置附近的图像进行处理,如果用户在第10个位置,那么我可能只获取接下来的图像而不是一次性获取所有图像。我会更新的。 - Jesus Dimrix

1
如果您想重复使用约30个小图像,可以将它们作为Bitmaps的软引用保存在内存中,并在离开带有ListViewFragmentActivity后回收所有内容。
例如,您的ImageView大小为55dp x 55dp,有30行图像。

DisplayManager:
(注:原文为HTML格式,已保留)
public static DP_55;//55 dp to px, do not count it each time, define it!
public static defineSize(Activity activity)
{
     DisplayMetrics metrics = new DisplayMetrics();
     activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
     DP_55 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 55, metrics);
}

您的活动或片段:

public HashMap<String, SoftReference<Bitmap>> bitmaps = new HashMap<>();

文件互联网加载图像,作为位图,缩放到您的大小(55 dp),并放入字典中:
if (!bitmaps.containsKey(urlOrPath)) {
     //Load 'bitmap' and put to dictionary:
     bitmaps.put(urlOrPath, new SoftReference<>(
                Bitmap.createScaledBitmap(
                        bitmap,
                        DisplayManager.DP_55, DisplayManager.DP_55, true)));
}
else //Just reuse it!
     iv_image.setImageBitmap(bitmaps.get(urlOrPath).get());

如何回收它:

Iterator<Map.Entry<String, SoftReference<Bitmap>>> iterator = bitmaps.entrySet().iterator();
while (iterator.hasNext()) {
       iterator.next().getValue().get().recycle();
       iterator.remove();
}

如果ImageView的大小较小且行数<50,则无法超出40MB的限制,并且在滚动最大速度后加载图像。
否则,请使用ImageLoaders(如Glide、Picasso等)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接