关于android:ListView中的图像的延迟加载

Lazy load of images in ListView

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

图像总数不固定。


以下是我创建的用于保存应用程序当前显示的图像的内容。请注意,这里使用的"log"对象是我在Android中对最终日志类的自定义包装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.wilson.android.library;

/*
 Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/
import java.io.IOException;

public class DrawableManager {
    private final Map<String, Drawable> drawableMap;

    public DrawableManager() {
        drawableMap = new HashMap<String, Drawable>();
    }

    public Drawable fetchDrawable(String urlString) {
        if (drawableMap.containsKey(urlString)) {
            return drawableMap.get(urlString);
        }

        Log.d(this.getClass().getSimpleName(),"image url:" + urlString);
        try {
            InputStream is = fetch(urlString);
            Drawable drawable = Drawable.createFromStream(is,"src");


            if (drawable != null) {
                drawableMap.put(urlString, drawable);
                Log.d(this.getClass().getSimpleName(),"got a thumbnail drawable:" + drawable.getBounds() +","
                        + drawable.getIntrinsicHeight() +"," + drawable.getIntrinsicWidth() +","
                        + drawable.getMinimumHeight() +"," + drawable.getMinimumWidth());
            } else {
              Log.w(this.getClass().getSimpleName(),"could not get thumbnail");
            }

            return drawable;
        } catch (MalformedURLException e) {
            Log.e(this.getClass().getSimpleName(),"fetchDrawable failed", e);
            return null;
        } catch (IOException e) {
            Log.e(this.getClass().getSimpleName(),"fetchDrawable failed", e);
            return null;
        }
    }

    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
        if (drawableMap.containsKey(urlString)) {
            imageView.setImageDrawable(drawableMap.get(urlString));
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };

        Thread thread = new Thread() {
            @Override
            public void run() {
                //TODO : set imageView to a"pending" image
                Drawable drawable = fetchDrawable(urlString);
                Message message = handler.obtainMessage(1, drawable);
                handler.sendMessage(message);
            }
        };
        thread.start();
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpGet request = new HttpGet(urlString);
        HttpResponse response = httpClient.execute(request);
        return response.getEntity().getContent();
    }
}


我用图片制作了一个简单的惰性列表演示(位于Github)。

Basic Usage

1
2
ImageLoader imageLoader=new ImageLoader(context); ...
imageLoader.DisplayImage(url, imageView);

Don't forget to add the
following permissions to your AndroidManifest.xml:

1
2
 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Please

create only one instance of ImageLoader and reuse it all around your
application. This way image caching will be much more efficient.

它可能对某人有帮助。它在后台线程中下载图像。图像被缓存在SD卡和内存中。缓存实现非常简单,只需演示即可。我解码图像的采样,以减少内存消耗。我还尝试正确处理回收视图。

Alt text


我推荐开源仪器通用图像加载器。它最初基于FedorVlasov的Lazylist项目,从那时起已经得到了很大的改进。

  • 多线程图像加载
  • 可以对ImageLoader的配置进行广泛的调整(线程执行器、下载器、解码器、内存和磁盘缓存、显示图像选项等)
  • 在内存和/或设备文件系统(或SD卡)中缓存图像的可能性
  • "倾听"加载过程的可能性
  • 可以使用单独的选项自定义每个显示图像调用
  • 小部件支持
  • Android 2.0+支持

></P></p>
<div class=


性能的多线程处理,由GillesDebunne指导。

这是来自Android开发者博客。建议的代码使用:

  • AsyncTasks
  • 硬的,有限的尺寸,FIFO cache
  • 一个软的、容易的garbage collected缓存。
  • 下载时使用占位符Drawable

enter image description here


更新:请注意,这个答案现在非常无效。垃圾收集器在SoftReference和Weakreference上起着积极的作用,因此此代码不适用于新的应用程序。(相反,尝试使用其他答案中建议的通用图像加载器之类的库。)

多亏了詹姆斯的代码,包龙建议使用软参考。我在James的代码上实现了软引用更改。不幸的是,软引用导致我的图像被垃圾收集得太快。在我的例子中,没有软参考资料是可以的,因为我的列表大小是有限的,我的图像是小的。

一年前有一个关于谷歌群组的软引用的讨论:链接到线程。作为过早垃圾收集的解决方案,他们建议使用dalvik.system.vmruntime.setMinimumHeapsize()手动设置VM堆大小,这对我来说不是很有吸引力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public DrawableManager() {
    drawableMap = new HashMap<String, SoftReference<Drawable>>();
}

public Drawable fetchDrawable(String urlString) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null)
            return drawable;
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(),"image url:" + urlString);
    try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is,"src");
        drawableRef = new SoftReference<Drawable>(drawable);
        drawableMap.put(urlString, drawableRef);
        if (Constants.LOGGING) Log.d(this.getClass().getSimpleName(),"got a thumbnail drawable:" + drawable.getBounds() +","
                + drawable.getIntrinsicHeight() +"," + drawable.getIntrinsicWidth() +","
                + drawable.getMinimumHeight() +"," + drawable.getMinimumWidth());
        return drawableRef.get();
    } catch (MalformedURLException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(),"fetchDrawable failed", e);
        return null;
    } catch (IOException e) {
        if (Constants.LOGGING) Log.e(this.getClass().getSimpleName(),"fetchDrawable failed", e);
        return null;
    }
}

public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
    SoftReference<Drawable> drawableRef = drawableMap.get(urlString);
    if (drawableRef != null) {
        Drawable drawable = drawableRef.get();
        if (drawable != null) {
            imageView.setImageDrawable(drawableRef.get());
            return;
        }
        // Reference has expired so remove the key from drawableMap
        drawableMap.remove(urlString);
    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            imageView.setImageDrawable((Drawable) message.obj);
        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a"pending" image
            Drawable drawable = fetchDrawable(urlString);
            Message message = handler.obtainMessage(1, drawable);
            handler.sendMessage(message);
        }
    };
    thread.start();
}


毕加索

使用杰克·沃顿的毕加索图书馆。(来自ActionBarsherlock开发人员的完美图像加载库)

一个强大的Android图像下载和缓存库。

图像为Android应用程序添加了急需的上下文和视觉功能。毕加索允许在应用程序中以一行代码轻松加载图像!

1
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

许多在Android上加载图像的常见陷阱都是由毕加索自动处理的:

在适配器中处理ImageView回收和下载取消。使用最少内存的复杂图像转换。自动内存和磁盘缓存。

毕加索杰克沃顿图书馆

滑翔

Glide是一个用于Android的快速高效的开源媒体管理框架,它将媒体解码、内存和磁盘缓存以及资源池打包成一个简单易用的界面。

Glide支持提取、解码和显示视频静像、图像和动画gif。Glide包含一个灵活的API,允许开发人员插入几乎任何网络堆栈。默认情况下,glide使用自定义的基于httpurlconnection的堆栈,但还包括实用程序库插件到Google的Volley项目或Square的OKHTTP库。

1
Glide.with(this).load("http://goo.gl/h8qOq7").into(imageView);

glide的主要焦点是使滚动任何类型的图像列表尽可能平滑和快速,但是glide对于几乎任何需要获取、调整和显示远程图像的情况都是有效的。

滑动图像加载库

Facebook的壁画

Fresco是一个在Android应用程序中显示图像的强大系统。

壁画负责图像的加载和显示,所以你不必这么做。它将从网络、本地存储或本地资源加载图像,并在图像到达之前显示一个占位符。它有两个级别的缓存:一个在内存中,另一个在内部存储器中。

壁画吉特布

在android 4.x及更低版本中,fresco将图像放在android内存的一个特殊区域。这使您的应用程序运行得更快,并且更少地遭受可怕的内存不足的错误。

壁画文献


高性能装载机-在检查了这里建议的方法之后,我用了本的解决方案,做了一些改动-

  • 我意识到使用Drawables比使用位图更快,所以我改用Drawables。

  • 使用SoftReference很好,但是它会使缓存的图像被删除的太频繁,所以我添加了一个包含图像引用的链接列表,防止删除图像,直到它达到预定的大小。

  • 要打开inputstream,我使用了java.net.urlconnection,它允许我使用web缓存(您需要先设置响应缓存,但这是另一个情况)

  • 我的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    import java.util.Map;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.Collections;
    import java.util.WeakHashMap;
    import java.lang.ref.SoftReference;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
    import android.graphics.drawable.Drawable;
    import android.widget.ImageView;
    import android.os.Handler;
    import android.os.Message;
    import java.io.InputStream;
    import java.net.MalformedURLException;
    import java.io.IOException;
    import java.net.URL;
    import java.net.URLConnection;

    public class DrawableBackgroundDownloader {    

    private final Map<String, SoftReference<Drawable>> mCache = new HashMap<String, SoftReference<Drawable>>();  
    private final LinkedList <Drawable> mChacheController = new LinkedList <Drawable> ();
    private ExecutorService mThreadPool;  
    private final Map<ImageView, String> mImageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());  

    public static int MAX_CACHE_SIZE = 80;
    public int THREAD_POOL_SIZE = 3;

    /**
     * Constructor
     */
    public DrawableBackgroundDownloader() {  
        mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);  
    }  


    /**
     * Clears all instance data and stops running threads
     */
    public void Reset() {
        ExecutorService oldThreadPool = mThreadPool;
        mThreadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        oldThreadPool.shutdownNow();

        mChacheController.clear();
        mCache.clear();
        mImageViews.clear();
    }  

    public void loadDrawable(final String url, final ImageView imageView,Drawable placeholder) {  
        mImageViews.put(imageView, url);  
        Drawable drawable = getDrawableFromCache(url);  

        // check in UI thread, so no concurrency issues  
        if (drawable != null) {  
            //Log.d(null,"Item loaded from mCache:" + url);  
            imageView.setImageDrawable(drawable);  
        } else {  
            imageView.setImageDrawable(placeholder);  
            queueJob(url, imageView, placeholder);  
        }  
    }


    private Drawable getDrawableFromCache(String url) {  
        if (mCache.containsKey(url)) {  
            return mCache.get(url).get();  
        }  

        return null;  
    }

    private synchronized void putDrawableInCache(String url,Drawable drawable) {  
        int chacheControllerSize = mChacheController.size();
        if (chacheControllerSize > MAX_CACHE_SIZE)
            mChacheController.subList(0, MAX_CACHE_SIZE/2).clear();

        mChacheController.addLast(drawable);
        mCache.put(url, new SoftReference<Drawable>(drawable));

    }  

    private void queueJob(final String url, final ImageView imageView,final Drawable placeholder) {  
        /* Create handler in UI thread. */  
        final Handler handler = new Handler() {  
            @Override  
            public void handleMessage(Message msg) {  
                String tag = mImageViews.get(imageView);  
                if (tag != null && tag.equals(url)) {
                    if (imageView.isShown())
                        if (msg.obj != null) {
                            imageView.setImageDrawable((Drawable) msg.obj);  
                        } else {  
                            imageView.setImageDrawable(placeholder);  
                            //Log.d(null,"fail" + url);  
                        }
                }  
            }  
        };  

        mThreadPool.submit(new Runnable() {  
            @Override  
            public void run() {  
                final Drawable bmp = downloadDrawable(url);
                // if the view is not visible anymore, the image will be ready for next time in cache
                if (imageView.isShown())
                {
                    Message message = Message.obtain();  
                    message.obj = bmp;
                    //Log.d(null,"Item downloaded:" + url);  

                    handler.sendMessage(message);
                }
            }  
        });  
    }  



    private Drawable downloadDrawable(String url) {  
        try {  
            InputStream is = getInputStream(url);

            Drawable drawable = Drawable.createFromStream(is, url);
            putDrawableInCache(url,drawable);  
            return drawable;  

        } catch (MalformedURLException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  

        return null;  
    }  


    private InputStream getInputStream(String urlString) throws MalformedURLException, IOException {
        URL url = new URL(urlString);
        URLConnection connection;
        connection = url.openConnection();
        connection.setUseCaches(true);
        connection.connect();
        InputStream response = connection.getInputStream();

        return response;
    }
    }


    我接受过这个Android培训,我认为它在下载图片时非常出色,不会阻塞主用户界面。它还处理缓存和处理滚动浏览许多图像:高效加载大型位图


    1。毕加索允许在应用程序中以一行代码轻松加载图像!

    使用Gradle:

    1
    implementation 'com.squareup.picasso:picasso:2.71828'

    只有一行代码!

    1
    Picasso.get().load("http://i.imgur.com/DvpvklR.png").into(imageView);

    2。glide一个面向Android的图像加载和缓存库,专注于平滑滚动

    使用Gradle:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    repositories {
      mavenCentral()
      google()
    }

    dependencies {
       implementation 'com.github.bumptech.glide:glide:4.7.1'
       annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
    }

    //对于简单视图:

    1
      Glide.with(this).load("http://i.imgur.com/DvpvklR.png").into(imageView);

    三。Fresco是一个在Android中显示图像的强大系统。应用程序。Fresco负责图像加载和显示,因此您没有去。

    壁画入门


    我编写了一个教程,解释如何在ListView中延迟加载图像。我将详细介绍回收和并发性问题。我还使用固定线程池来防止产生大量线程。

    在ListView教程中延迟加载图像


    我的方法是启动一个线程,在后台下载图片,并为每个列表项传递一个回调。当图像下载完成后,它会调用回调来更新列表项的视图。

    然而,当您回收视图时,这种方法并不能很好地工作。


    我只想再添加一个好例子,XML适配器。因为它被谷歌使用,我也在使用同样的逻辑来避免内存不足的错误。

    基本上,这个图片下载器是你的答案(因为它涵盖了你的大部分需求)。其中一些您也可以实现。


    我一直在使用新安卓Volley库com.android.volley.toolbox.NetworkImageView的networkImageView,它看起来工作得很好。显然,这与Google Play和其他新的Google应用程序中使用的视图相同。绝对值得一看。

    • Google I/O 2013 Volley图像缓存教程

    • 开发者谷歌活动


    这是安卓系统上的一个常见问题,许多人通过多种方式解决了这个问题。在我看来,我所看到的最好的解决方案是一个相对较新的图书馆,叫做毕加索。以下是重点:

    • 开源,但以Jake Wharton为领袖的ActionBarsherlock声名远扬。
    • 使用一行代码从网络或应用程序资源异步加载图像
    • 自动ListView检测
    • 自动磁盘和内存缓存
    • 可以进行自定义转换
    • 许多可配置选项
    • 超简单API
    • 经常更新


    嗯,从互联网上传图片的时间有很多解决方案。您也可以使用库android查询。它将为您提供所有必需的活动。确保你想做什么,并阅读图书馆的wiki页面。解决了图像加载限制。

    这是我的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @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;
    }

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


    我认为这个问题在Android开发人员中非常流行,有很多这样的库声称可以解决这个问题,但似乎只有少数库是正确的。aquery就是这样一个图书馆,但它在各个方面都比它们中的大多数要好,值得一试。


    你一定要试试这个万能装载机是最好的。我在完成了很多次延迟加载后使用这个。

    通用图像加载器

    特征

    • 多线程图像加载(异步或同步)
    • 图像加载器配置的广泛定制(线程执行器、下载器、解码器、内存和磁盘缓存、显示图像选项等)
    • 每个显示图像调用的许多自定义选项(存根图像、缓存开关、解码选项、位图处理和显示等)
    • 内存和/或磁盘上的图像缓存(设备的文件系统或SD卡)
    • 监听加载过程(包括下载进度)

    Android 2.0+支持

    enter image description here


    看看Shutterbug,applidium的轻量级SDWebImage(iOS上的一个不错的库)和Android的端口。它支持异步缓存,存储失败的URL,很好地处理并发性,并包含有用的子类。

    拉请求(和错误报告)也是受欢迎的!


    对于不确定要使用哪个库进行延迟加载图像的人来说,这只是一个快速提示:

    有四种基本方法。

  • DIY=>不是最好的解决方案,但是对于一些图片,如果你想不费吹灰之力使用其他库的话

  • Volley的懒惰加载库=>来自Android的家伙。它很好,而且所有的东西都没有很好的文档记录,因此使用起来很困难。

  • 毕加索:这是一个简单的解决方案,你甚至可以指定你想要引入的确切图像大小。对于必须处理大量图像的应用程序来说,它的使用非常简单,但可能不会非常"性能"。

  • UIL:延迟加载图像的最佳方法。您可以缓存图像(当然您需要权限),初始化一次加载程序,然后完成您的工作。迄今为止我所见过的最成熟的异步映像加载库。


  • DroidParts的ImageFetcher需要零配置才能启动。

    • 使用磁盘和内存中最近使用的(LRU)缓存。
    • 有效地解码图像。
    • 支持在后台线程中修改位图。
    • 有简单的交叉淡入淡出。
    • 有图像加载进度回调。

    克隆DroidPartsGram例如:

    Enter image description here


    Novoda也有一个非常懒惰的图片加载库,许多应用程序,如Songkick、Podio、Secretdj和ImageSearch都使用它们的库。

    他们的库托管在Github上,他们也有一个相当活跃的问题跟踪程序。他们的项目似乎也相当活跃,在写这个回复时提交了超过300个。


    检查我的Lazylist叉子。基本上,我通过延迟ImageView的调用来改进Lazylist,并创建两种方法:

  • 当你需要放像"加载图像…"之类的东西时。
  • 当您需要显示下载的图像时。
  • 我还通过在这个对象中实现一个单例来改进了ImageLoader。


    以上所有的代码都有自己的价值,但根据我的个人经验,请尝试一下毕加索。

    毕加索是一个专门用于此目的的库,实际上它将自动管理缓存和所有其他网络操作。您必须在项目中添加库,只需编写一行代码即可从远程URL加载图像。

    请访问:http://code.tutsplus.com/tutorials/android-sdk-working-with-picasso--cms-22149


    使用glide库。它适用于我,也适用于您的代码。它既适用于图像,也适用于gif。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ImageView imageView = (ImageView) findViewById(R.id.test_image);
        GlideDrawableImageViewTarget imagePreview = new GlideDrawableImageViewTarget(imageView);
        Glide
                .with(this)
                .load(url)
                .listener(new RequestListener<String, GlideDrawable>() {
                    @Override
                    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {                      
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                        return false;
                    }
                })
                .into(imagePreview);
    }


    如果你想像facebook那样显示闪光的布局,那就有一个官方的facebook库。Facebook闪影安卓

    它可以处理所有的事情,您只需要将所需的设计代码以嵌套的方式放入Shimmer框架中。这是一个示例代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <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代码。

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

    在渐变文件中添加此依赖项。

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

    这是它的样子.Shimmer Android screenshot


    UrlimageViewHelper是一个非常棒的库,可以帮助您完成这项工作。


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

    你可以从这里下载JAR文件

    1
    AQuery androidAQuery = new AQuery(this);

    举个例子:

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

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


    试一试。它有非常简单的方法来异步加载和缓存图像。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    public class ImageDownloader {

    Map<String, Bitmap> imageCache;

    public ImageDownloader() {
        imageCache = new HashMap<String, Bitmap>();

    }

    // download function
    public void download(String url, ImageView imageView) {
        if (cancelPotentialDownload(url, imageView)) {

            // Caching code right here
            String filename = String.valueOf(url.hashCode());
            File f = new File(getCacheDirectory(imageView.getContext()),
                    filename);

            // Is the bitmap in our memory cache?
            Bitmap bitmap = null;

            bitmap = (Bitmap) imageCache.get(f.getPath());

            if (bitmap == null) {

                bitmap = BitmapFactory.decodeFile(f.getPath());

                if (bitmap != null) {
                    imageCache.put(f.getPath(), bitmap);
                }

            }
            // No? download it
            if (bitmap == null) {
                try {
                    BitmapDownloaderTask task = new BitmapDownloaderTask(
                            imageView);
                    DownloadedDrawable downloadedDrawable = new DownloadedDrawable(
                            task);
                    imageView.setImageDrawable(downloadedDrawable);
                    task.execute(url);
                } catch (Exception e) {
                    Log.e("Error==>", e.toString());
                }

            } else {
                // Yes? set the image
                imageView.setImageBitmap(bitmap);
            }
        }
    }

    // cancel a download (internal only)
    private static boolean cancelPotentialDownload(String url,
            ImageView imageView) {
        BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

        if (bitmapDownloaderTask != null) {
            String bitmapUrl = bitmapDownloaderTask.url;
            if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
                bitmapDownloaderTask.cancel(true);
            } else {
                // The same URL is already being downloaded.
                return false;
            }
        }
        return true;
    }

    // gets an existing download if one exists for the imageview
    private static BitmapDownloaderTask getBitmapDownloaderTask(
            ImageView imageView) {
        if (imageView != null) {
            Drawable drawable = imageView.getDrawable();
            if (drawable instanceof DownloadedDrawable) {
                DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
                return downloadedDrawable.getBitmapDownloaderTask();
            }
        }
        return null;
    }

    // our caching functions
    // Find the dir to save cached images
    private static File getCacheDirectory(Context context) {
        String sdState = android.os.Environment.getExternalStorageState();
        File cacheDir;

        if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
            File sdDir = android.os.Environment.getExternalStorageDirectory();

            // TODO : Change your diretcory here
            cacheDir = new File(sdDir,"data/ToDo/images");
        } else
            cacheDir = context.getCacheDir();

        if (!cacheDir.exists())
            cacheDir.mkdirs();
        return cacheDir;
    }

    private void writeFile(Bitmap bmp, File f) {
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(f);
            bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (Exception ex) {
            }
        }
    }

    // download asynctask
    public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
        private String url;
        private final WeakReference<ImageView> imageViewReference;

        public BitmapDownloaderTask(ImageView imageView) {
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        @Override
        // Actual download method, run in the task thread
        protected Bitmap doInBackground(String... params) {
            // params comes from the execute() call: params[0] is the url.
            url = (String) params[0];
            return downloadBitmap(params[0]);
        }

        @Override
        // Once the image is downloaded, associates it to the imageView
        protected void onPostExecute(Bitmap bitmap) {
            if (isCancelled()) {
                bitmap = null;
            }

            if (imageViewReference != null) {
                ImageView imageView = imageViewReference.get();
                BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
                // Change bitmap only if this process is still associated with
                // it
                if (this == bitmapDownloaderTask) {
                    imageView.setImageBitmap(bitmap);

                    // cache the image

                    String filename = String.valueOf(url.hashCode());
                    File f = new File(
                            getCacheDirectory(imageView.getContext()), filename);

                    imageCache.put(f.getPath(), bitmap);

                    writeFile(bitmap, f);
                }
            }
        }

    }

    static class DownloadedDrawable extends ColorDrawable {
        private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;

        public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
            super(Color.WHITE);
            bitmapDownloaderTaskReference = new WeakReference<BitmapDownloaderTask>(
                    bitmapDownloaderTask);
        }

        public BitmapDownloaderTask getBitmapDownloaderTask() {
            return bitmapDownloaderTaskReference.get();
        }
    }

    // the actual download code
    static Bitmap downloadBitmap(String url) {
        HttpParams params = new BasicHttpParams();
        params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
                HttpVersion.HTTP_1_1);
        HttpClient client = new DefaultHttpClient(params);
        final HttpGet getRequest = new HttpGet(url);

        try {
            HttpResponse response = client.execute(getRequest);
            final int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                Log.w("ImageDownloader","Error" + statusCode
                        +" while retrieving bitmap from" + url);
                return null;
            }

            final HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = null;
                try {
                    inputStream = entity.getContent();
                    final Bitmap bitmap = BitmapFactory
                            .decodeStream(inputStream);
                    return bitmap;
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    entity.consumeContent();
                }
            }
        } catch (Exception e) {
            // Could provide a more explicit error message for IOException or
            // IllegalStateException
            getRequest.abort();
            Log.w("ImageDownloader","Error while retrieving bitmap from"
                    + url + e.toString());
        } finally {
            if (client != null) {
                // client.close();
            }
        }
        return null;
     }
    }

    我有这个问题并实现了lRucache。我相信您需要API 12及以上版本或使用兼容v4库。lurcache是快速内存,但它也有预算,所以如果您担心可以使用diskcache…所有这些都在缓存位图中描述。

    现在,我将提供我的实现,它是我从类似这样的任何地方调用的单例实现:

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

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

    以下是在检索Web映像时在适配器的getview中缓存然后调用上述代码的理想代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    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);
            }
        }
    }

    你可以尝试使用aquery android库来延迟加载图片和列表视图…下面的代码可以帮助您…..从此处下载库。

    1
    2
    AQuery aq = new AQuery(mContext);
    aq.id(R.id.image1).image("http://data.whicdn.com/images/63995806/original.jpg");

    一些答案已经提到使用各种图像库,如通用图像加载器和AndroidImage加载器等。这是一个老问题,但对于仍在寻找类似问题的任何人来说,有几个这样的库用于图像加载/缓存。


    另一种方法是通过getView()方法中的线程中的适配器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Thread pics_thread = new Thread(new Runnable() {
        @Override
        public void run() {
            Bitmap bitmap = getPicture(url);
            if(bitmap != null) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        holder.imageview.setImageBitmap(bitmap);            
                        adapter.notifyDataSetChanged();
                    }                      
                });            
            }      
        }                      
    });

    pics_thread.start();

    当然,您应该始终缓存您的图像以避免额外的操作,您可以将图像放在哈希映射数组中,检查该图像是否存在于数组中,如果不存在,则继续执行该线程,或者从哈希映射数组加载图像。另外,一定要检查内存是否泄漏,位图和可绘制文件通常占用大量内存。由您来优化代码。


    我使用DroidQuery。有两种从URL加载图像的机制。第一个(简写)是:

    1
    $.with(myView).image(url);

    这可以很容易地添加到ArrayAdaptergetView(...)方法中。

    longhand方法将提供更多的控制,这里甚至没有讨论过选项(如缓存和回调),但是可以在这里找到指定输出大小为200px x 200px的基本实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    $.ajax(new AjaxOptions().url(url)
        .type("GET")
        .dataType("image")
        .imageWidth(200).imageHeight(200)
        .success(new Function() {
            @Override
            public void invoke($ droidQuery, Object... params) {
                myImageView.setImageBitmap((Bitmap) params[0]);
            }
        })
        .error(new Function() {
            @Override
            public void invoke($ droidQuery, Object... params) {
                AjaxError e = (AjaxError) params[0];
                Log.e("$","Error" + e.status +":" + e.error);
            }
        })
    );

    我发现滑翔比Picasso更好。我用毕加索在32上加载每个图片的大小,每个图片的大小都是200-500KB,我总是得到OOM。但是Glide解决了我所有的OOM问题。


    使用下面的类在ListView中下载和加载图像。下载后它会缓存每个图像。同时加载图像和延迟加载。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    package com.fudiyoxpress.images;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Collections;
    import java.util.Map;
    import java.util.WeakHashMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Handler;
    import android.widget.ImageView;

    import com.fudiyoxpress.R;
    import com.fudiyoxpress.config.Config;
    import com.fudiyoxpress.twitter.ScaleBitmap;

    public class ImageLoader {

        // Initialize MemoryCache
        MemoryCache memoryCache = new MemoryCache();

        FileCache fileCache;

        Context C;

        // Create Map (collection) to store image and image url in key value pair
        private Map<ImageView, String> imageViews = Collections
                .synchronizedMap(new WeakHashMap<ImageView, String>());
        ExecutorService executorService;

        // handler to display images in UI thread
        Handler handler = new Handler();

        public ImageLoader(Context context) {

            C = context;
            fileCache = new FileCache(context);

            // Creates a thread pool that reuses a fixed number of
            // threads operating off a shared unbounded queue.
            executorService = Executors.newFixedThreadPool(5);

        }

        // default image show in list (Before online image download)
        final int stub_id = R.drawable.restlogoplaceholder;

        public void DisplayImage(String url, ImageView imageView, Context context,
                boolean header_flag) {

            Bitmap largeIcon = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.restlogoplaceholder);
            header_flag = false;
            // Store image and url in Map
            imageViews.put(imageView, url);

            // Check image is stored in MemoryCache Map or not (see
            // MemoryCache.java)
            Bitmap bitmap = memoryCache.get(url);

            if (bitmap != null) {
                // if image is stored in MemoryCache Map then
                // Show image in listview row
                Bitmap b = ScaleBitmap
                        .getScaledBitmap(context, bitmap, header_flag);
                imageView.setImageBitmap(b);

            } else {
                // queue Photo to download from url
                queuePhoto(url, imageView, header_flag);

                // Before downloading image show default image
                imageView.setImageBitmap(ScaleBitmap.getScaledBitmap(context,
                        largeIcon, header_flag));

            }
        }



        private void queuePhoto(String url, ImageView imageView, boolean header_flag) {
            // Store image and url in PhotoToLoad object
            PhotoToLoad p = new PhotoToLoad(url, imageView, header_flag);

            // pass PhotoToLoad object to PhotosLoader runnable class
            // and submit PhotosLoader runnable to executers to run runnable
            // Submits a PhotosLoader runnable task for execution

            executorService.submit(new PhotosLoader(p));
        }

        // Task for the queue
        private class PhotoToLoad {
            public String url;
            public ImageView imageView;
            public boolean b;

            public PhotoToLoad(String u, ImageView i, boolean header_flag) {
                url = u;
                imageView = i;
                b = header_flag;
            }
        }

        class PhotosLoader implements Runnable {
            PhotoToLoad photoToLoad;

            PhotosLoader(PhotoToLoad photoToLoad) {
                this.photoToLoad = photoToLoad;
            }

            @Override
            public void run() {
                try {
                    // Check if image already downloaded
                    if (imageViewReused(photoToLoad))
                        return;
                    // download image from web url
                    Bitmap bmp = getBitmap(photoToLoad.url);

                    // set image data in Memory Cache
                    memoryCache.put(photoToLoad.url, bmp);

                    if (imageViewReused(photoToLoad))
                        return;

                    // Get bitmap to display
                    BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);

                    // Causes the Runnable bd (BitmapDisplayer) to be added to the
                    // message queue.
                    // The runnable will be run on the thread to which this handler
                    // is attached.
                    // BitmapDisplayer run method will call
                    handler.post(bd);

                } catch (Throwable th) {
                    // th.printStackTrace();
                }
            }
        }

        private Bitmap getBitmap(String url) {
            File f = fileCache.getFile(url);

            // from SD cache
            // CHECK : if trying to decode file which not exist in cache return null
            Bitmap b = decodeFile(f);
            if (b != null)
                return b;

            // Download image file from web
            try {

                // // download the image
                Bitmap bitmap = null;

                URL imageURL = null;
                try {

                    imageURL = new URL(Config.WEB_URL +"/ServeBlob?id=" + url);

                    HttpURLConnection connection = (HttpURLConnection) imageURL
                            .openConnection();
                    connection.setDoInput(true);
                    connection.connect();
                    // if(!(new File(imageURL.toString())).exists())
                    // {
                    // imageURL=new URL("");
                    // }
                    InputStream inputStream = connection.getInputStream();

                    // Constructs a new FileOutputStream that writes to
                    // file
                    // if file not exist then it will create file
                    OutputStream os = new FileOutputStream(f);

                    // See Utils class CopyStream method
                    // It will each pixel from input stream and
                    // write pixels to output stream (file)
                    Utils.CopyStream(inputStream, os);

                    os.close();

                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inSampleSize = 8;

                    bitmap = BitmapFactory.decodeStream(inputStream, null, options);

                } catch (IOException e) {

                    // e.printStackTrace();
                }

                // Now file created and going to resize file with defined height
                // Decodes image and scales it to reduce memory consumption
                bitmap = decodeFile(f);

                return bitmap;

            } catch (Throwable ex) {
                ex.printStackTrace();
                if (ex instanceof OutOfMemoryError)
                    memoryCache.clear();
                return null;
            }
        }

        // Decodes image and scales it to reduce memory consumption
        private Bitmap decodeFile(File f) {

            try {

                // Decode image size
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                FileInputStream stream1 = new FileInputStream(f);
                BitmapFactory.decodeStream(stream1, null, o);
                stream1.close();

                // Find the correct scale value. It should be the power of 2.

                // Set width/height of recreated image
                final int REQUIRED_SIZE = 85;

                int width_tmp = o.outWidth, height_tmp = o.outHeight;
                int scale = 1;
                while (true) {
                    if (width_tmp / 2 < REQUIRED_SIZE
                            || height_tmp / 2 < REQUIRED_SIZE)
                        break;
                    width_tmp /= 2;
                    height_tmp /= 2;
                    scale *= 2;
                }

                // decode with current scale values
                BitmapFactory.Options o2 = new BitmapFactory.Options();
                o2.inSampleSize = scale;
                FileInputStream stream2 = new FileInputStream(f);
                Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
                stream2.close();
                return bitmap;

            } catch (FileNotFoundException e) {
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        boolean imageViewReused(PhotoToLoad photoToLoad) {

            String tag = imageViews.get(photoToLoad.imageView);
            // Check url is already exist in imageViews MAP
            if (tag == null || !tag.equals(photoToLoad.url))
                return true;
            return false;
        }

        // Used to display bitmap in the UI thread
        class BitmapDisplayer implements Runnable {
            Bitmap bitmap;
            PhotoToLoad photoToLoad;

            public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
                bitmap = b;
                photoToLoad = p;
            }

            public void run() {
                if (imageViewReused(photoToLoad))
                    return;

                // Show bitmap on UI
                if (bitmap != null) {
                    photoToLoad.imageView.setImageBitmap(ScaleBitmap
                            .getScaledBitmap(C, bitmap, photoToLoad.b));
                } else {

                }
                // photoToLoad.imageView.setImageResource(stub_id);

            }
        }

        public void clearCache() {
            // Clear cache directory downloaded images and stored data in maps
            memoryCache.clear();
            fileCache.clear();
        }

    }




    package com.fudiyoxpress.images;

    import java.util.Collections;
    import java.util.Iterator;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    import android.graphics.Bitmap;
    import android.util.Log;

    public class MemoryCache {

        private static final String TAG ="MemoryCache";

        //Last argument true for LRU ordering
        private Map<String, Bitmap> cache = Collections.synchronizedMap(
                new LinkedHashMap<String, Bitmap>(10,1.5f,true));

       //current allocated size
        private long size=0;

        //max memory cache folder used to download images in bytes
        private long limit = 1000000;

        public MemoryCache(){

            //use 25% of available heap size
            setLimit(Runtime.getRuntime().maxMemory()/4);
        }

        public void setLimit(long new_limit){

            limit=new_limit;
            Log.i(TAG,"MemoryCache will use up to"+limit/1024./1024.+"MB");
        }

        public Bitmap get(String id){
            try{
                if(!cache.containsKey(id))
                    return null;
                //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
                return cache.get(id);
            }catch(NullPointerException ex){
                ex.printStackTrace();
                return null;
            }
        }

        public void put(String id, Bitmap bitmap){
            try{
                if(cache.containsKey(id))
                    size-=getSizeInBytes(cache.get(id));
                cache.put(id, bitmap);
                size+=getSizeInBytes(bitmap);
                checkSize();
            }catch(Throwable th){
                th.printStackTrace();
            }
        }

        private void checkSize() {
            Log.i(TAG,"cache size="+size+" length="+cache.size());
            if(size>limit){
                Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated  
                while(iter.hasNext()){
                    Entry<String, Bitmap> entry=iter.next();
                    size-=getSizeInBytes(entry.getValue());
                    iter.remove();
                    if(size<=limit)
                        break;
                }
                Log.i(TAG,"Clean cache. New size"+cache.size());
            }
        }

        public void clear() {
            try{
                //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
                cache.clear();
                size=0;
            }catch(NullPointerException ex){
                ex.printStackTrace();
            }
        }

        long getSizeInBytes(Bitmap bitmap) {
            if(bitmap==null)
                return 0;
            return bitmap.getRowBytes() * bitmap.getHeight();
        }
    }




    package com.fudiyoxpress.images;

    import java.io.InputStream;
    import java.io.OutputStream;

    public class Utils {
        public static void CopyStream(InputStream is, OutputStream os)
        {
            final int buffer_size=1024;
            try
            {

                byte[] bytes=new byte[buffer_size];
                for(;;)
                {
                  //Read byte from input stream

                  int count=is.read(bytes, 0, buffer_size);
                  if(count==-1)
                      break;

                  //Write byte from output stream
                  os.write(bytes, 0, count);
                }
            }
            catch(Exception ex){}
        }
    }

    您可以使用一些第三方库,如PiccasoVolley来有效地延迟加载。您也可以通过实现以下内容来创建自己的

  • 实现从URL下载图像的代码

  • 实现存储和检索图像的缓存机制(使用android的LruCache进行缓存)


  • 您可以使用Greendroid的AsyncImageView。只需调用seturl我想这可能有助于做你不想做的事并参考以下链接:

    Greendroid的AsyncImageView链接


    除了异步加载数据缓存外,您可能需要UI缓存

    除了加载可见项数据外,您可能需要加载近似可见项数据

    例子:假设ListView可见项为[6,7,8,9,10],则可能需要加载[6,7,8,9,10]并预加载项[1,2,3,4,5]&;[11,12,13,14,15],因为用户可能会滚动到前页或后页。