Android图像缓存

发布于 2024-12-15 15:26:22 字数 22 浏览 0 评论 0原文

从网络下载图像后如何缓存图像?

How can I cache images after they are downloaded from web?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

抽个烟儿 2024-12-22 15:26:23

我尝试过 SoftReferences,它们在 Android 中被过度回收,我觉得没有必要使用它们

I've tried SoftReferences, they are too aggressively reclaimed in android that I felt there was no point using them

十年九夏 2024-12-22 15:26:23

正如 Thunder Rabbit 所建议的,ImageDownloader 是最适合这项工作的工具。我还在以下位置发现了该类的细微变化:

http://theandroidcoder。 com/utilities/android-image-download-and-caching/

两者的主要区别是ImageDownloader使用Android缓存系统,修改后的使用内部和外部存储作为缓存,保留缓存的图片无限期地或直到用户手动将其删除。作者还提到了Android 2.1的兼容性。

As Thunder Rabbit suggested, ImageDownloader is the best one for the job. I also found a slight variation of the class at:

http://theandroidcoder.com/utilities/android-image-download-and-caching/

The main difference between the two is that the ImageDownloader uses the Android caching system, and the modified one uses internal and external storage as caching, keeping the cached images indefinitely or until the user removes it manually. The author also mentions Android 2.1 compatibility.

琉璃繁缕 2024-12-22 15:26:23

这是乔的一个很好的接球。上面的代码示例有两个问题 - 一 - 响应对象不是 Bitmap 的实例(当我的 URL 引用 jpg 时,例如 http:\website.com\image.jpg,它是

org.apache.harmony.luni。 Internal.net.www.protocol.http.HttpURLConnectionImpl$LimitedInputStream)。

其次,正如 Joe 指出的,如果没有配置响应缓存,就不会发生缓存。 Android 开发人员只能滚动自己的缓存。这是一个这样做的示例,但它仅缓存在内存中,这实际上不是完整的解决方案。

http://codebycoffee.com/2010/06/29/using-responsecache -in-an-android-app/

URLConnection 缓存 API 描述如下:

http://download.oracle.com/javase/6/docs/technotes/ guides/net/http-cache.html

我仍然认为这是走这条路的一个不错的解决方案 - 但你仍然必须编写一个缓存。听起来很有趣,但我宁愿写功能。

This is a good catch by Joe. The code example above has two problems - one - the response object isn't an instance of Bitmap (when my URL references a jpg, like http:\website.com\image.jpg, its a

org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl$LimitedInputStream).

Second, as Joe points out, no caching occurs without a response cache being configured. Android developers are left to roll their own cache. Here's an example for doing so, but it only caches in memory, which really isn't the full solution.

http://codebycoffee.com/2010/06/29/using-responsecache-in-an-android-app/

The URLConnection caching API is described here:

http://download.oracle.com/javase/6/docs/technotes/guides/net/http-cache.html

I still think this is an OK solution to go this route - but you still have to write a cache. Sounds like fun, but I'd rather write features.

缱倦旧时光 2024-12-22 15:26:23

Android 官方培训部分对此有一个专门的条目: http://developer.android .com/training/displaying-bitmaps/cache-bitmap.html

该部分非常新,在提出问题时它不存在。

建议的解决方案是使用 LruCache。该类是在 Honeycomb 上引入的,但它也包含在兼容性库中。

您可以通过设置最大数量或条目来初始化 LruCache,它会自动对它们进行排序,并在超过限制时清理较少使用的条目。除此之外,它用作普通地图。

官方页面的示例代码:

private LruCache mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Get memory class of this device, exceeding this amount will throw an
    // OutOfMemory exception.
    final int memClass = ((ActivityManager) context.getSystemService(
            Context.ACTIVITY_SERVICE)).getMemoryClass();

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

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

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

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

以前 SoftReferences 是一个不错的选择,但现在不再是了,引用官方页面:

注意:过去,流行的内存缓存实现是
SoftReference 或 WeakReference 位图缓存,但这不是
受到推崇的。从Android 2.3(API Level 9)开始垃圾
收集器更积极地收集软/弱引用
这使得它们相当低效。另外,Android 3.0之前
(API 级别 11),位图的支持数据存储在本机中
未以可预测的方式释放的内存,可能
导致应用程序短暂超出其内存限制并崩溃。

There is a special entry on the official training section of Android about this: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

The section is quite new, it was not there when the question was asked.

The suggested solution is to use a LruCache. That class was introduced on Honeycomb, but it is also included on the compatibility library.

You can initialize a LruCache by setting the maximum number or entries and it will automatically sort them your you and clean them less used ones when you go over the limit. Other than that it is used as a normal Map.

The sample code from the official page:

private LruCache mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Get memory class of this device, exceeding this amount will throw an
    // OutOfMemory exception.
    final int memClass = ((ActivityManager) context.getSystemService(
            Context.ACTIVITY_SERVICE)).getMemoryClass();

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

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

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

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

Previously SoftReferences were a good alternative, but not anymore, quoting from the official page:

Note: In the past, a popular memory cache implementation was a
SoftReference or WeakReference bitmap cache, however this is not
recommended. Starting from Android 2.3 (API Level 9) the garbage
collector is more aggressive with collecting soft/weak references
which makes them fairly ineffective. In addition, prior to Android 3.0
(API Level 11), the backing data of a bitmap was stored in native
memory which is not released in a predictable manner, potentially
causing an application to briefly exceed its memory limits and crash.

会发光的星星闪亮亮i 2024-12-22 15:26:23

考虑使用通用图像加载器库(作者:谢尔盖·塔拉塞维奇。它附带:

  • 多线程图像加载。它允许您定义线程池大小、
  • 图像缓存在内存、设备的文件系统和 SD 卡上。
  • 可以侦听加载进度和加载事件

Universal Image Loader 允许对下载的图像进行详细的缓存管理,具有以下缓存配置:

  • UsingFreqLimitedMemoryCache最不频繁的 i> 当超过缓存大小限制时,使用的位图将被删除。
  • LRULimitedMemoryCache:当超出缓存大小限制时,最近使用的位图将被删除。
  • FIFOLimitedMemoryCache:当超过缓存大小限制时,采用先进先出规则进行删除。
  • LargestLimitedMemoryCache:当超过缓存大小限制时,最大位图将被删除。
  • LimitedAgeMemoryCache:当缓存对象的年龄超过定义值时,该对象将被删除。
  • WeakMemoryCache:仅对位图进行弱引用的内存缓存。

一个简单的使用示例:

ImageView imageView = groupView.findViewById(R.id.imageView);
String imageUrl = "http://site.com/image.png"; 

ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
imageLoader.displayImage(imageUrl, imageView);

此示例使用默认的 UsingFreqLimitedMemoryCache

Consider using Universal Image Loader library by Sergey Tarasevich. It comes with:

  • Multithread image loading. It lets you can define the thread pool size
  • Image caching in memory, on device's file sytem and SD card.
  • Possibility to listen to loading progress and loading events

Universal Image Loader allows detailed cache management for downloaded images, with the following cache configurations:

  • UsingFreqLimitedMemoryCache: The least frequently used bitmap is deleted when the cache size limit is exceeded.
  • LRULimitedMemoryCache: The least recently used bitmap is deleted when the cache size limit is exceeded.
  • FIFOLimitedMemoryCache: The FIFO rule is used for deletion when the cache size limit is exceeded.
  • LargestLimitedMemoryCache: The largest bitmap is deleted when the cache size limit is exceeded.
  • LimitedAgeMemoryCache: The Cached object is deleted when its age exceeds defined value.
  • WeakMemoryCache: A memory cache with only weak references to bitmaps.

A simple usage example:

ImageView imageView = groupView.findViewById(R.id.imageView);
String imageUrl = "http://site.com/image.png"; 

ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
imageLoader.displayImage(imageUrl, imageView);

This example uses the default UsingFreqLimitedMemoryCache.

忆依然 2024-12-22 15:26:23

对我来说真正有用的是在我的主类上设置 ResponseCache:

try {
   File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
   long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
   HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { } 

以及

connection.setUseCaches(true);

在下载位图时。

http://practicaldroid.blogspot.com/2013/01/utilizing -http-response-cache.html

What actually worked for me was setting ResponseCache on my Main class:

try {
   File httpCacheDir = new File(getApplicationContext().getCacheDir(), "http");
   long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
   HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) { } 

and

connection.setUseCaches(true);

when downloading bitmap.

http://practicaldroid.blogspot.com/2013/01/utilizing-http-response-cache.html

那支青花 2024-12-22 15:26:23

Google 的 libs-for-android 有一个很好的库,用于管理图像和文件缓存。

http://code.google.com/p/libs-for-android/

Google's libs-for-android has a nice libraries for managing image and file cache.

http://code.google.com/p/libs-for-android/

旧情勿念 2024-12-22 15:26:23

我已经为此苦苦挣扎了一段时间。使用软引用的答案会很快丢失数据。建议实例化 RequestCache 的答案太混乱了,而且我永远找不到完整的示例。

但是 ImageDownloader.java 可以工作对我来说太棒了。它使用 HashMap 直到达到容量或直到发生清除超时,然后将内容转移到 SoftReference,从而利用两全其美。

I had been wrestling with this for some time; the answers using SoftReferences would lose their data too quickly. The answers that suggest instantiating a RequestCache were too messy, plus I could never find a full example.

But ImageDownloader.java works wonderfully for me. It uses a HashMap until the capacity is reached or until the purge timeout occurs, then things get moved to a SoftReference, thereby using the best of both worlds.

浪漫之都 2024-12-22 15:26:23

甚至稍后回答,但我编写了一个 Android 图像管理器,它透明地处理缓存(内存和磁盘)。代码位于 Github https://github.com/felipecsl/Android-ImageManager

Even later answer, but I wrote an Android Image Manager that handles caching transparently (memory and disk). The code is on Github https://github.com/felipecsl/Android-ImageManager

拥抱我好吗 2024-12-22 15:26:23

迟到的答案,但我想我应该添加一个链接到我的网站,因为我已经写了一个教程如何为 android 制作图像缓存: http://squarewolf.nl/2010/11/android-image-cache/ 更新: 该页面有已被下线作为来源已经过时了。我和 @elenasys 一起建议使用 Ignition

因此,对于所有偶然发现这个问题但尚未找到解决方案的人:希望您喜欢! =D

Late answer, but I figured I should add a link to my site because I have written a tutorial how to make an image cache for android: http://squarewolf.nl/2010/11/android-image-cache/ Update: the page has been taken offline as the source was outdated. I join @elenasys in her advice to use Ignition.

So to all the people who stumble upon this question and haven't found a solution: hope you enjoy! =D

小情绪 2024-12-22 15:26:23

迟到的答案,但我认为这个库对缓存图像有很大帮助:
https://github.com/crypticminds/ColdStorage

只需用以下方式注释 ImageView
@LoadCache(R.id.id_of_my_image_view, "URL_to_downlaod_image_from) 它将负责下载图像并将其加载到图像视图中。您还可以指定占位符图像并加载动画。

注释的详细文档位于此处:-
https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation< /a>

Late answer but I think this library will help a lot with caching images :
https://github.com/crypticminds/ColdStorage.

Simply annotate the ImageView with
@LoadCache(R.id.id_of_my_image_view, "URL_to_downlaod_image_from) and it will take care of downloading the image and loading it into the image view. You can also specify a placeholder image and loading animation.

Detailed documentation of the annotation is present here :-
https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation

纸短情长 2024-12-22 15:26:22

现在重点是:使用系统缓存。

URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
  Bitmap bitmap = (Bitmap)response;
} 

提供内存和闪存缓存,与浏览器共享。

grr。我希望有人在我编写自己的缓存管理器之前告诉我这一点。

And now the punchline: use the system cache.

URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Object response = connection.getContent();
if (response instanceof Bitmap) {
  Bitmap bitmap = (Bitmap)response;
} 

Provides both memory and flash-rom cache, shared with the browser.

grr. I wish somebody had told ME that before i wrote my own cache manager.

祁梦 2024-12-22 15:26:22

关于上面优雅的 connection.setUseCaches 解决方案:遗憾的是,如果不做一些额外的努力,它就无法工作。您需要使用 ResponseCache.setDefault 安装 ResponseCache。否则,HttpURLConnection 将默默地忽略 setUseCaches(true) 位。

有关详细信息,请参阅 FileResponseCache.java 顶部的注释:

http://libs-for-android.googlecode.com/svn/reference/com/google/android/filecache/FileResponseCache.html

(我会发布这个在评论中,但我显然没有足够的SO业力。)

Regarding the elegant connection.setUseCaches solution above: sadly, it won't work without some additional effort. You will need to install a ResponseCache using ResponseCache.setDefault. Otherwise, HttpURLConnection will silently ignore the setUseCaches(true) bit.

See the comments at the top of FileResponseCache.java for details:

http://libs-for-android.googlecode.com/svn/reference/com/google/android/filecache/FileResponseCache.html

(I'd post this in a comment, but I apparently don't have enough SO karma.)

赴月观长安 2024-12-22 15:26:22

将它们转换为位图,然后将它们存储在集合(HashMap、列表等)中,或者您可以将它们写入 SD 卡上。

当使用第一种方法将它们存储在应用程序空间中时,您可能希望将它们包装在 java.lang.ref.SoftReference 中,特别是如果它们的数量很大(以便在危机期间对它们进行垃圾收集)。不过,这可能会导致重新加载。

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

将它们写入 SD 卡上不需要重新加载;只是一个用户权限。

Convert them into Bitmaps and then either store them in a Collection(HashMap,List etc.) or you can write them on the SDcard.

When storing them in application space using the first approach, you might want to wrap them around a java.lang.ref.SoftReference specifically if their numbers is large (so that they are garbage collected during crisis). This could ensue a Reload though.

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

writing them on SDcard will not require a Reload; just a user-permission.

反目相谮 2024-12-22 15:26:22

使用LruCache高效缓存图像。您可以从 Android 开发者网站阅读有关 LruCache 的信息

我在android中使用了下面的图像下载和缓存解决方案。您可以按照以下步骤操作:

第 1 步:
将类命名为ImagesCache。我已经为此类使用了 Singleton 对象

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class ImagesCache 
{
    private  LruCache<String, Bitmap> imagesWarehouse;

    private static ImagesCache cache;

    public static ImagesCache getInstance()
    {
        if(cache == null)
        {
            cache = new ImagesCache();
        }

        return cache;
    }

    public void initializeCache()
    {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);

        final int cacheSize = maxMemory / 8;

        System.out.println("cache size = "+cacheSize);

        imagesWarehouse = new LruCache<String, Bitmap>(cacheSize)
                {
                    protected int sizeOf(String key, Bitmap value) 
                    {
                        // The cache size will be measured in kilobytes rather than number of items.

                        int bitmapByteCount = value.getRowBytes() * value.getHeight();

                        return bitmapByteCount / 1024;
                    }
                };
    }

    public void addImageToWarehouse(String key, Bitmap value)
    {       
        if(imagesWarehouse != null && imagesWarehouse.get(key) == null)
        {
            imagesWarehouse.put(key, value);
        }
    }

    public Bitmap getImageFromWarehouse(String key)
    {
        if(key != null)
        {
            return imagesWarehouse.get(key);
        }
        else
        {
            return null;
        }
    }

    public void removeImageFromWarehouse(String key)
    {
        imagesWarehouse.remove(key);
    }

    public void clearCache()
    {
        if(imagesWarehouse != null)
        {
            imagesWarehouse.evictAll();
        }       
    }

}

第 2 步:

创建另一个名为 DownloadImageTask 的类,如果位图在缓存中不可用,则使用该类,它将从此处下载:

public class DownloadImageTask extends AsyncTask<String, Void, Bitmap>
{   
    private int inSampleSize = 0;

    private String imageUrl;

    private BaseAdapter adapter;

    private ImagesCache cache;

    private int desiredWidth, desiredHeight;

    private Bitmap image = null;

    private ImageView ivImageView;

    public DownloadImageTask(BaseAdapter adapter, int desiredWidth, int desiredHeight) 
    {
        this.adapter = adapter;

        this.cache = ImagesCache.getInstance();

        this.desiredWidth = desiredWidth;

        this.desiredHeight = desiredHeight;
    }

    public DownloadImageTask(ImagesCache cache, ImageView ivImageView, int desireWidth, int desireHeight)
    {
        this.cache = cache;

        this.ivImageView = ivImageView;

        this.desiredHeight = desireHeight;

        this.desiredWidth = desireWidth;
    }

    @Override
    protected Bitmap doInBackground(String... params) 
    {
        imageUrl = params[0];

        return getImage(imageUrl);
    }

    @Override
    protected void onPostExecute(Bitmap result) 
    {
        super.onPostExecute(result);

        if(result != null)
        {
            cache.addImageToWarehouse(imageUrl, result);

            if(ivImageView != null)
            {
                ivImageView.setImageBitmap(result);
            }
            else if(adapter != null)
            {
                adapter.notifyDataSetChanged();
            }
        }
    }

    private Bitmap getImage(String imageUrl)
    {   
        if(cache.getImageFromWarehouse(imageUrl) == null)
        {
            BitmapFactory.Options options = new BitmapFactory.Options();

            options.inJustDecodeBounds = true;

            options.inSampleSize = inSampleSize;

            try
            {
                URL url = new URL(imageUrl);

                HttpURLConnection connection = (HttpURLConnection)url.openConnection();

                InputStream stream = connection.getInputStream();

                image = BitmapFactory.decodeStream(stream, null, options);

                int imageWidth = options.outWidth;

                int imageHeight = options.outHeight;

                if(imageWidth > desiredWidth || imageHeight > desiredHeight)
                {   
                    System.out.println("imageWidth:"+imageWidth+", imageHeight:"+imageHeight);

                    inSampleSize = inSampleSize + 2;

                    getImage(imageUrl);
                }
                else
                {   
                    options.inJustDecodeBounds = false;

                    connection = (HttpURLConnection)url.openConnection();

                    stream = connection.getInputStream();

                    image = BitmapFactory.decodeStream(stream, null, options);

                    return image;
                }
            }

            catch(Exception e)
            {
                Log.e("getImage", e.toString());
            }
        }

        return image;
    }

第3步:ActivityAdapter使用

注意:如果您想从Activity的url加载图像类。使用 DownloadImageTask 的第二个构造函数,但如果您想从 Adapter 显示图像,请使用 DownloadImageTask 的第一个构造函数(例如,您有一个图像ListView 并且您正在设置“适配器”中的图像)

活动中的使用情况:

ImageView imv = (ImageView) findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();//Singleton instance handled in ImagesCache class.
cache.initializeCache();

String img = "your_image_url_here";

Bitmap bm = cache.getImageFromWarehouse(img);

if(bm != null)
{
  imv.setImageBitmap(bm);
}
else
{
  imv.setImageBitmap(null);

  DownloadImageTask imgTask = new DownloadImageTask(cache, imv, 300, 300);//Since you are using it from `Activity` call second Constructor.

  imgTask.execute(img);
}

适配器中的使用情况:

ImageView imv = (ImageView) rowView.findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();
cache.initializeCache();

String img = "your_image_url_here";

Bitmap bm = cache.getImageFromWarehouse(img);

if(bm != null)
{
  imv.setImageBitmap(bm);
}
else
{
  imv.setImageBitmap(null);

  DownloadImageTask imgTask = new DownloadImageTask(this, 300, 300);//Since you are using it from `Adapter` call first Constructor.

  imgTask.execute(img);
}

注意:

cache.initializeCache() 您可以在应用程序的第一个 Activity 中使用此语句。初始化缓存后,如果您使用 ImagesCache 实例,则无需每次都初始化它。

我从来不擅长解释事情,但希望这能帮助初学者了解如何使用 LruCache 进行缓存及其用法:)

编辑:

现在有一些非常著名的库例如 PicassoGlide 可用于在 Android 应用程序中非常有效地加载图像。尝试这个非常简单且有用的库 Picasso for androidAndroid 版 Glide。您无需担心缓存图像。

Picasso 通常可以在您的应用程序中轻松加载图像
在一行代码中!

Glide 就像 Picasso 一样,可以加载并显示来自许多地方的图像
源,同时还要处理缓存并保持低内存
进行图像处理时的影响。已经被官方使用了
Google 应用程序(例如 Google I/O 2015 的应用程序)同样受欢迎
作为毕加索。在本系列中,我们将探讨差异和
Glide 相对于 Picasso 的优势。

您还可以访问博客了解Glide 和 Picasso 之间的区别

Use LruCache to cache images efficiently. You can read about LruCache from Android Developer site

I've used below solution for Images download and caching in android. You can follow steps below:

STEP 1:
make Class Named ImagesCache. I've used Singleton object for this class

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class ImagesCache 
{
    private  LruCache<String, Bitmap> imagesWarehouse;

    private static ImagesCache cache;

    public static ImagesCache getInstance()
    {
        if(cache == null)
        {
            cache = new ImagesCache();
        }

        return cache;
    }

    public void initializeCache()
    {
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);

        final int cacheSize = maxMemory / 8;

        System.out.println("cache size = "+cacheSize);

        imagesWarehouse = new LruCache<String, Bitmap>(cacheSize)
                {
                    protected int sizeOf(String key, Bitmap value) 
                    {
                        // The cache size will be measured in kilobytes rather than number of items.

                        int bitmapByteCount = value.getRowBytes() * value.getHeight();

                        return bitmapByteCount / 1024;
                    }
                };
    }

    public void addImageToWarehouse(String key, Bitmap value)
    {       
        if(imagesWarehouse != null && imagesWarehouse.get(key) == null)
        {
            imagesWarehouse.put(key, value);
        }
    }

    public Bitmap getImageFromWarehouse(String key)
    {
        if(key != null)
        {
            return imagesWarehouse.get(key);
        }
        else
        {
            return null;
        }
    }

    public void removeImageFromWarehouse(String key)
    {
        imagesWarehouse.remove(key);
    }

    public void clearCache()
    {
        if(imagesWarehouse != null)
        {
            imagesWarehouse.evictAll();
        }       
    }

}

STEP 2:

make another class named DownloadImageTask which is used if bitmap is not available in cache it will download it from here:

public class DownloadImageTask extends AsyncTask<String, Void, Bitmap>
{   
    private int inSampleSize = 0;

    private String imageUrl;

    private BaseAdapter adapter;

    private ImagesCache cache;

    private int desiredWidth, desiredHeight;

    private Bitmap image = null;

    private ImageView ivImageView;

    public DownloadImageTask(BaseAdapter adapter, int desiredWidth, int desiredHeight) 
    {
        this.adapter = adapter;

        this.cache = ImagesCache.getInstance();

        this.desiredWidth = desiredWidth;

        this.desiredHeight = desiredHeight;
    }

    public DownloadImageTask(ImagesCache cache, ImageView ivImageView, int desireWidth, int desireHeight)
    {
        this.cache = cache;

        this.ivImageView = ivImageView;

        this.desiredHeight = desireHeight;

        this.desiredWidth = desireWidth;
    }

    @Override
    protected Bitmap doInBackground(String... params) 
    {
        imageUrl = params[0];

        return getImage(imageUrl);
    }

    @Override
    protected void onPostExecute(Bitmap result) 
    {
        super.onPostExecute(result);

        if(result != null)
        {
            cache.addImageToWarehouse(imageUrl, result);

            if(ivImageView != null)
            {
                ivImageView.setImageBitmap(result);
            }
            else if(adapter != null)
            {
                adapter.notifyDataSetChanged();
            }
        }
    }

    private Bitmap getImage(String imageUrl)
    {   
        if(cache.getImageFromWarehouse(imageUrl) == null)
        {
            BitmapFactory.Options options = new BitmapFactory.Options();

            options.inJustDecodeBounds = true;

            options.inSampleSize = inSampleSize;

            try
            {
                URL url = new URL(imageUrl);

                HttpURLConnection connection = (HttpURLConnection)url.openConnection();

                InputStream stream = connection.getInputStream();

                image = BitmapFactory.decodeStream(stream, null, options);

                int imageWidth = options.outWidth;

                int imageHeight = options.outHeight;

                if(imageWidth > desiredWidth || imageHeight > desiredHeight)
                {   
                    System.out.println("imageWidth:"+imageWidth+", imageHeight:"+imageHeight);

                    inSampleSize = inSampleSize + 2;

                    getImage(imageUrl);
                }
                else
                {   
                    options.inJustDecodeBounds = false;

                    connection = (HttpURLConnection)url.openConnection();

                    stream = connection.getInputStream();

                    image = BitmapFactory.decodeStream(stream, null, options);

                    return image;
                }
            }

            catch(Exception e)
            {
                Log.e("getImage", e.toString());
            }
        }

        return image;
    }

STEP 3: Usage from your Activity or Adapter

Note: If you want to load image from url from Activity Class. Use the second Constructor of DownloadImageTask, but if you want to display image from Adapter use first Constructor of DownloadImageTask (for example you have a image in ListView and you are setting image from 'Adapter')

USAGE FROM ACTIVITY:

ImageView imv = (ImageView) findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();//Singleton instance handled in ImagesCache class.
cache.initializeCache();

String img = "your_image_url_here";

Bitmap bm = cache.getImageFromWarehouse(img);

if(bm != null)
{
  imv.setImageBitmap(bm);
}
else
{
  imv.setImageBitmap(null);

  DownloadImageTask imgTask = new DownloadImageTask(cache, imv, 300, 300);//Since you are using it from `Activity` call second Constructor.

  imgTask.execute(img);
}

USAGE FROM ADAPTER:

ImageView imv = (ImageView) rowView.findViewById(R.id.imageView);
ImagesCache cache = ImagesCache.getInstance();
cache.initializeCache();

String img = "your_image_url_here";

Bitmap bm = cache.getImageFromWarehouse(img);

if(bm != null)
{
  imv.setImageBitmap(bm);
}
else
{
  imv.setImageBitmap(null);

  DownloadImageTask imgTask = new DownloadImageTask(this, 300, 300);//Since you are using it from `Adapter` call first Constructor.

  imgTask.execute(img);
}

Note:

cache.initializeCache() you can use this statement in the very first Activity of your application. Once you've initialized the cache you would never need to initialized it every time if you are using ImagesCache instance.

I am never good at explaining things but hope this will help the beginners that how to cache using LruCache and its usage :)

EDIT:

Now a days there are very famous libraries known as Picasso and Glide which can be used to load images very efficiently in android app. Try this very simple and usefull library Picasso for android and Glide For Android. You do not need to worry about cache images.

Picasso allows for hassle-free image loading in your application—often
in one line of code!

Glide, just like Picasso, can load and display images from many
sources, while also taking care of caching and keeping a low memory
impact when doing image manipulations. It has been used by official
Google apps (like the app for Google I/O 2015) and is just as popular
as Picasso. In this series, we're going to explore the differences and
advantages of Glide over Picasso.

You can also visit blog for difference between Glide and Picasso

翻了热茶 2024-12-22 15:26:22

要下载图像并将其保存到存储卡,您可以这样做。

//First create a new URL object 
URL url = new URL("http://www.google.co.uk/logos/holiday09_2.gif")

//Next create a file, the example below will save to the SDCARD using JPEG format
File file = new File("/sdcard/example.jpg");

//Next create a Bitmap object and download the image to bitmap
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());

//Finally compress the bitmap, saving to the file previously created
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));

不要忘记将互联网权限添加到您的清单中:

<uses-permission android:name="android.permission.INTERNET" />

To download an image and save to the memory card you can do it like this.

//First create a new URL object 
URL url = new URL("http://www.google.co.uk/logos/holiday09_2.gif")

//Next create a file, the example below will save to the SDCARD using JPEG format
File file = new File("/sdcard/example.jpg");

//Next create a Bitmap object and download the image to bitmap
Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());

//Finally compress the bitmap, saving to the file previously created
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));

Don't forget to add the Internet permission to your manifest:

<uses-permission android:name="android.permission.INTERNET" />
烟燃烟灭 2024-12-22 15:26:22

我会考虑使用 droidfu 的图像缓存。它实现了内存中和基于磁盘的图像缓存。您还可以获得一个利用 ImageCache 库的 WebImageView。

以下是 droidfu 和 WebImageView 的完整描述:
http://brainflush.wordpress .com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/

I would consider using droidfu's image cache. It implements both an in-memory and disk-based image cache. You also get a WebImageView that takes advantage of the ImageCache library.

Here is the full description of droidfu and WebImageView:
http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryadapter/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文