我正在使用ListView来显示与这些图像相关的一些图像和标题。我正在从互联网上获取图像。是否有一种方法可以延迟加载图像,以便在文本显示时,UI不会被阻止,图像在下载时显示?

图像总数不是固定的。


当前回答

我一直在使用新的Android Volley Library com.Android.Volley.toolbox.NetworkImageView中的NetworkImageView,它似乎工作得很好。显然,这是Google Play和其他新的Google应用程序中使用的相同视图。绝对值得一看。

Google I/O 2013凌空图像缓存教程开发者Google活动

其他回答

嗯,从互联网加载图像有很多解决方案。您也可以使用Android Query库。它将为您提供所有必需的活动。确保您想做什么,并阅读库wiki页面。并解决了图像加载限制。

这是我的代码:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.row, null);
    }

    ImageView imageview = (ImageView) v.findViewById(R.id.icon);
    AQuery aq = new AQuery(convertView);

    String imageUrl = "http://www.vikispot.com/z/images/vikispot/android-w.png";

    aq.id(imageview).progress(this).image(imageUrl, true, true, 0, 0, new BitmapAjaxCallback() {
        @Override
        public void callback(String url, ImageView iv, Bitmap bm, AjaxStatus status) {
            iv.setImageBitmap(bm);
        }
    ));

    return v;
}

它应该可以解决您的延迟加载问题。

您可以使用一些第三方库(如Piccaso或Volley)进行有效的延迟加载。您还可以通过实现以下内容创建自己的

用于从url下载图像的实现代码实现用于存储和检索图像的缓存机制(使用android的LruCache进行缓存)

我遇到了这个问题,并实现了lruCache。我相信你需要API 12或更高版本,或者使用兼容的v4库。lurCache是快速内存,但它也有预算,所以如果你担心,你可以使用磁盘缓存。。。这都在缓存位图中描述。

现在我将提供我的实现,它是我从任何地方调用的单例,如下所示:

//Where the first is a string and the other is a imageview to load.

DownloadImageTask.getInstance().loadBitmap(avatarURL, iv_avatar);

以下是理想的代码,在检索web图像时,缓存并在适配器的getView中调用上述代码:

public class DownloadImageTask {

    private LruCache<String, Bitmap> mMemoryCache;

    /* Create a singleton class to call this from multiple classes */

    private static DownloadImageTask instance = null;

    public static DownloadImageTask getInstance() {
        if (instance == null) {
            instance = new DownloadImageTask();
        }
        return instance;
    }

    //Lock the constructor from public instances
    private DownloadImageTask() {

        // Get max available VM memory, exceeding this amount will throw an
        // OutOfMemory exception. Stored in kilobytes as LruCache takes an
        // int in its constructor.
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;

        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                // The cache size will be measured in kilobytes rather than
                // number of items.
                return bitmap.getByteCount() / 1024;
            }
        };
    }

    public void loadBitmap(String avatarURL, ImageView imageView) {
        final String imageKey = String.valueOf(avatarURL);

        final Bitmap bitmap = getBitmapFromMemCache(imageKey);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
        } else {
            imageView.setImageResource(R.drawable.ic_launcher);

            new DownloadImageTaskViaWeb(imageView).execute(avatarURL);
        }
    }

    private void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

    private Bitmap getBitmapFromMemCache(String key) {
        return mMemoryCache.get(key);
    }

    /* A background process that opens a http stream and decodes a web image. */

    class DownloadImageTaskViaWeb extends AsyncTask<String, Void, Bitmap> {
        ImageView bmImage;

        public DownloadImageTaskViaWeb(ImageView bmImage) {
            this.bmImage = bmImage;
        }

        protected Bitmap doInBackground(String... urls) {

            String urldisplay = urls[0];
            Bitmap mIcon = null;
            try {
                InputStream in = new java.net.URL(urldisplay).openStream();
                mIcon = BitmapFactory.decodeStream(in);

            } 
            catch (Exception e) {
                Log.e("Error", e.getMessage());
                e.printStackTrace();
            }

            addBitmapToMemoryCache(String.valueOf(urldisplay), mIcon);

            return mIcon;
        }

        /* After decoding we update the view on the main UI. */
        protected void onPostExecute(Bitmap result) {
            bmImage.setImageBitmap(result);
        }
    }
}

更新:如果您正在寻找2020年由Kotlin Coroutines支持的解决方案,请尝试Coil。

Coil是Coroutine Image Loader的缩写。

特征

快速:Coil执行许多优化,包括内存和磁盘缓存、在内存中对图像进行下采样、重新使用位图、自动暂停/取消请求等。轻量级:Coil为您的APK添加了约2000个方法(适用于已经使用OkHttp和Coroutines的应用程序),这与毕加索不相上下,明显少于Glide和Fresco。易于使用:Coil的API利用了Kotlin的语言特性,以实现简单和最小的样板。现代:Coil首先是Kotlin,它使用了包括Coroutines、OkHttp、Okio和AndroidX Lifecycles在内的现代库。

渐变设置:

线圈在mavenCentral()上可用。

implementation("io.coil-kt:coil:1.0.0")

快速入门

要将图像加载到ImageView中,请使用加载扩展函数:

// URL
imageView.load("https://www.example.com/image.jpg")

// Resource
imageView.load(R.drawable.image)

// File
imageView.load(File("/path/to/image.jpg"))

或在后台线程上

// Coil (suspends the current coroutine; non-blocking and thread safe)
val request = ImageRequest.Builder(context)
    .data(url)
    .size(width, height)
    .build()
val drawable = context.imageLoader.execute(request).drawable

您也可以从Picasso/Glide迁移

此处提供完整文档

我写了一篇教程,解释如何在列表视图中延迟加载图像。我详细讨论了回收和并发的问题。我还使用固定线程池来防止产生大量线程。

在Listview教程中延迟加载图像