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

图像总数不是固定的。


当前回答

如果你想像Facebook一样显示Shimmer布局,有一个官方的Facebook库。FaceBook Shimmer Android

它可以处理所有的事情,你只需要将你想要的设计代码以嵌套的方式放在闪闪发光的框架中。这是一个示例代码。

<com.facebook.shimmer.ShimmerFrameLayout
     android:id=“@+id/shimmer_view_container”
     android:layout_width=“wrap_content”
     android:layout_height="wrap_content"
     shimmer:duration="1000">

 <here will be your content to display />

</com.facebook.shimmer.ShimmerFrameLayout>

这是它的java代码。

ShimmerFrameLayout shimmerContainer = (ShimmerFrameLayout) findViewById(R.id.shimmer_view_container);
shimmerContainer.startShimmerAnimation();

在渐变文件中添加此相关性。

implementation 'com.facebook.shimmer:shimmer:0.1.0@aar'

这是它的样子。

其他回答

我遇到了这个问题,并实现了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);
        }
    }
}

我发现滑翔机比毕加索更好。我使用picasso加载了大约32张图片,每张图片的大小约为200-500KB,而且我总是得到OOM。但滑翔机解决了我所有的OOM问题。

我这样做的方式是启动一个线程,在后台下载图像,并为每个列表项传递一个回调。当图像下载完成后,它将调用回调,以更新列表项的视图。

然而,当您回收视图时,这种方法不太有效。

我已经关注了这个Android培训,我认为它在下载图像而不阻塞主UI方面做得很好。它还处理缓存和滚动许多图像:高效加载大型位图

我可以推荐一种类似魅力的不同方式:Android Query。

您可以从这里下载JAR文件

AQuery androidAQuery = new AQuery(this);

例如:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);

它非常快速和准确,使用它,您可以找到更多的功能,如加载时的动画、获取位图(如果需要)等。