Bộ nhớ đệm hình ảnh Android


Câu trả lời:


177

Và bây giờ là punchline: sử dụng bộ đệm hệ thống.

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

Cung cấp cả bộ nhớ và bộ nhớ cache flash-rom, được chia sẻ với trình duyệt.

grr. Tôi ước ai đó đã nói với tôi rằng trước khi tôi viết trình quản lý bộ đệm của riêng mình.


1
Wow, đây là một cách cực kỳ thanh lịch để làm điều này, cảm ơn rất nhiều. Nó không chậm hơn trình quản lý bộ đệm đơn giản của riêng tôi và bây giờ tôi không cần phải làm công việc dọn phòng trên thư mục thẻ SD.
Kevin đọc

11
connection.getContent()luôn trả về InputStream cho tôi, tôi đang làm gì sai?
Tyler Collier

3
Nếu bây giờ tôi cũng có thể đặt ngày hết hạn cho nội dung cho bộ đệm thì cuộc sống của tôi sẽ dễ dàng hơn rất nhiều :)
Janusz

11
@Scienceprodigy không biết BitmapLoader là gì, chắc chắn không có trong bất kỳ thư viện Android tiêu chuẩn nào tôi biết, nhưng ít nhất nó đã đưa tôi đi đúng hướng. Bitmap response = BitmapFactory.decodeStream((InputStream)connection.getContent());
Stephen Fuhry

6
Hãy chắc chắn để xem câu trả lời của Joe bên dưới về các bước bổ sung bạn cần thực hiện để bộ đệm hoạt động
Keith

65

Về connection.setUseCachesgiải pháp tao nhã ở trên: thật đáng buồn, nó sẽ không hoạt động nếu không có thêm nỗ lực. Bạn sẽ cần phải cài đặt ResponseCachebằng cách sử dụng ResponseCache.setDefault. Nếu không, HttpURLConnectionsẽ âm thầm bỏ quasetUseCaches(true) bit.

Xem các bình luận ở đầu FileResponseCache.javađể biết chi tiết:

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

(Tôi sẽ đăng bài này trong một bình luận, nhưng rõ ràng tôi không có đủ nghiệp lực.)


Đây là tập tin
Telémako

2
Khi bạn sử dụng một HttpResponseCache, bạn có thể tìm thấy HttpResponseCache.getHitCount()trả về 0. Tôi không chắc nhưng tôi nghĩ đó là vì máy chủ web bạn yêu cầu không sử dụng các tiêu đề bộ đệm trong trường hợp đó. Để làm cho bộ nhớ đệm hoạt động nào, sử dụng connection.addRequestProperty("Cache-Control", "max-stale=" + MAX_STALE_CACHE);.
Almer

1
Liên kết tìm kiếm mã của Google đã chết (một lần nữa?), Vui lòng cập nhật liên kết.
Felix D.

Ngoài ra, tôi không chắc liệu hành vi này có được khắc phục hay không. Vì một số lý do, việc trả lại 304 từ máy chủ sẽ treo HUC khi sử dụng .getContent()phương thức vì các phản hồi 304 không có phần phản hồi liên quan theo tiêu chuẩn RFC.
TheRealChx101

27

Chuyển đổi chúng thành Bitmap và sau đó lưu trữ chúng trong Bộ sưu tập (HashMap, Danh sách, v.v.) hoặc bạn có thể viết chúng trên SDcard.

Khi lưu trữ chúng trong không gian ứng dụng bằng cách sử dụng phương pháp đầu tiên, bạn có thể muốn bọc chúng xung quanh java.lang.ref.SoftReference nếu số lượng của chúng lớn (để chúng được thu gom rác trong khủng hoảng). Điều này có thể xảy ra sau đó Tải lại.

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

viết chúng trên SDcard sẽ không yêu cầu Tải lại; chỉ cần sự cho phép của người dùng


Làm thế nào chúng ta có thể viết hình ảnh trên sd hoặc bộ nhớ điện thoại?
d-man

Để lưu hình ảnh trên thẻ SD: Bạn có thể cam kết luồng hình ảnh được đọc từ máy chủ từ xa vào bộ nhớ bằng các thao tác I / O tệp thông thường hoặc nếu bạn đã chuyển đổi hình ảnh của mình thành các đối tượng Bitmap, bạn có thể sử dụng phương thức Bitmap.compress ().
Samuh

@ d-man Tôi khuyên bạn nên ghi đĩa vào trước và sau đó lấy Uritham chiếu đường dẫn mà bạn có thể chuyển đến ImageViewvà các chế độ xem tùy chỉnh khác. Bởi vì mỗi lần bạn compress, bạn sẽ mất chất lượng. Tất nhiên điều này chỉ đúng với các thuật toán mất mát. Phương pháp này cũng sẽ cho phép bạn thậm chí lưu trữ một hàm băm của tệp và sử dụng nó vào lần tới khi bạn yêu cầu tệp từ máy chủ thông qua If-None-MatchETagcác tiêu đề.
TheRealChx101

@ TheRealChx101 bạn có thể vui lòng giúp hiểu ý của bạn lần sau khi bạn yêu cầu tệp từ máy chủ thông qua các tiêu đề If-none-Match và ETag , về cơ bản tôi đang tìm cách tiếp cận giải pháp trong đó hình ảnh vẫn nên sử dụng bộ đệm cục bộ để xác định giai đoạn HOẶC nếu điều này không thể đạt được thì bất cứ khi nào nội dung cho URL thay đổi, nó sẽ phản ánh trong ứng dụng với cái mới nhất và lưu vào bộ nhớ cache.
CoDe

@CoDe Visit link này cho bây giờ, android.jlelse.eu/...
TheRealChx101

27

Sử dụng LruCacheđể lưu trữ hình ảnh hiệu quả. Bạn có thể đọc về LruCachetừ trang web Nhà phát triển Android

Tôi đã sử dụng giải pháp dưới đây để tải xuống hình ảnh và bộ nhớ đệm trong Android. Bạn có thể làm theo các bước dưới đây:

BƯỚC 1: làm cho lớp được đặt tên ImagesCache. Tôi đã sử dụngSingleton 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();
        }       
    }

}

BƯỚC 2:

tạo một lớp khác có tên DownloadImageTask được sử dụng nếu bitmap không có sẵn trong bộ đệm, nó sẽ tải xuống từ đây:

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;
    }

BƯỚC 3: Sử dụng từ ActivityhoặcAdapter

Lưu ý: Nếu bạn muốn tải hình ảnh từ url từ ActivityClass. Sử dụng Trình xây dựng thứ hai của DownloadImageTask, nhưng nếu bạn muốn hiển thị hình ảnh từ Adaptersử dụng Trình xây dựng thứ nhất của DownloadImageTask(ví dụ: bạn có một hình ảnh trong ListViewvà bạn đang đặt hình ảnh từ 'Bộ điều hợp')

SỬ DỤNG TỪ HOẠT ĐỘNG:

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);
}

SỬ DỤNG TỪ QUẢNG CÁO:

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);
}

Ghi chú:

cache.initializeCache()bạn có thể sử dụng câu lệnh này trong Hoạt động đầu tiên của ứng dụng của bạn. Khi bạn đã khởi tạo bộ đệm, bạn sẽ không bao giờ cần phải khởi tạo nó mỗi lần nếu bạn đang sử dụng ImagesCachethể hiện.

Tôi không bao giờ giỏi trong việc giải thích mọi thứ nhưng hy vọng điều này sẽ giúp những người mới bắt đầu biết cách sử dụng bộ đệm LruCachevà cách sử dụng :)

BIÊN TẬP:

Ngày nay, có những thư viện rất nổi tiếng được biết đến PicassoGlidecó thể được sử dụng để tải hình ảnh rất hiệu quả trong ứng dụng Android. Hãy thử thư viện Picasso rất đơn giản và hữu ích này cho AndroidGlide For Android . Bạn không cần phải lo lắng về hình ảnh bộ nhớ cache.

Picasso cho phép tải hình ảnh không rắc rối trong ứng dụng của bạn thường xuyên trong một dòng mã!

Glide, giống như Picasso, có thể tải và hiển thị hình ảnh từ nhiều nguồn, đồng thời chăm sóc bộ nhớ đệm và giữ tác động bộ nhớ thấp khi thực hiện các thao tác hình ảnh. Nó đã được sử dụng bởi các ứng dụng chính thức của Google (như ứng dụng cho Google I / O 2015) và cũng phổ biến như Picasso. Trong loạt bài này, chúng ta sẽ khám phá sự khác biệt và lợi thế của Glide so với Picasso.

Bạn cũng có thể truy cập blog để biết sự khác biệt giữa Glide và Picasso


3
Câu trả lời và giải thích nổi bật! Tôi nghĩ rằng đây là giải pháp tốt nhất vì nó hoạt động khi ngoại tuyến và sử dụng Android LruCache. Tôi thấy giải pháp của edrowland không hoạt động ở chế độ máy bay ngay cả với sự bổ sung của Joe, đòi hỏi nhiều nỗ lực hơn để tích hợp. Btw, có vẻ như Android hoặc mạng cung cấp một lượng bộ nhớ đệm đáng kể ngay cả khi bạn không làm gì thêm. (Một nit nhỏ: để sử dụng mẫu getImageFromWareHouse, chữ 'H' phải là chữ thường để khớp.) Cảm ơn!
Edwin Evans

1
giải thích tuyệt vời :)
XtreemDeveloper

Bạn có thể giải thích phương thức getImage (), cụ thể là nó làm gì với kích thước hình ảnh và cách nó xảy ra. Tôi không hiểu ví dụ tại sao bạn lại gọi hàm bên trong và cách nó hoạt động.
Greyshack

1
Upvote cho điều if(cache == null)đó đã giải quyết vấn đề của tôi! :)
Ô. Garcia

1
Cũng xem câu trả lời Edited của tôi ở cuối. Tôi đã đề cập về các thư viện nổi tiếng được sử dụng bởi hầu hết các nhà phát triển bây giờ. Hãy thử những Picasso: square.github.io/picasso và Glide: futurestud.io/blog/glide-getting-started
Zubair Ahmed

18

Để tải xuống một hình ảnh và lưu vào thẻ nhớ, bạn có thể làm như thế này.

//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));

Đừng quên thêm quyền Internet vào bảng kê khai của bạn:

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

10
Tại sao bạn giải mã JPEG và sau đó mã hóa lại? Bạn được phục vụ tốt hơn khi tải URL xuống một mảng byte, sau đó sử dụng mảng byte đó để tạo Bitmap của bạn và ghi ra một Tệp. Mỗi khi bạn giải mã và mã hóa lại JPEG, chất lượng hình ảnh sẽ tệ hơn.
CommonsWare

2
Điểm công bằng, là nhiều hơn cho tốc độ sau đó bất cứ điều gì. Mặc dù, nếu được lưu dưới dạng một mảng byte và tệp nguồn không phải là JPEG thì tệp có cần phải được chuyển đổi không? "decodeByteArray" từ SDK Trả về "Ảnh bitmap được giải mã hoặc null nếu dữ liệu hình ảnh không thể được giải mã" vì vậy điều này khiến tôi nghĩ rằng nó luôn luôn giải mã dữ liệu hình ảnh vì vậy điều này có cần mã hóa lại không?
Ljdawson

Nói về hiệu quả, sẽ không hiệu quả nếu thay vì vượt qua FileOutputStream, chúng ta sẽ vượt qua BufferedOutputStream?
Samuh

1
tôi không đề xuất hình ảnh lưu vào bộ nhớ SD của bạn. một khi ứng dụng được gỡ cài đặt, các hình ảnh sẽ không bị xóa, khiến thẻ sd bị lấp đầy bởi rác vô dụng. lưu hình ảnh vào thư mục bộ nhớ cache của ứng dụng được ưu tiên IMO
james

Với giới hạn APK là 50mb, bộ nhớ đệm vào thẻ SD có thể là cách duy nhất cho các nhà phát triển.
Ljdawson

13

Tôi sẽ xem xét sử dụng bộ nhớ cache hình ảnh của droidfu. Nó thực hiện cả bộ nhớ cache hình ảnh trong bộ nhớ và trên đĩa. Bạn cũng nhận được một WebImageView tận dụng thư viện ImageCache.

Dưới đây là mô tả đầy đủ về droidfu và WebImageView: http://brainflush.wordpress.com/2009/11/23/droid-fu-part-2-webimageview-and-webgalleryad CHƯƠNG /


Anh ta đã tái cấu trúc mã của mình từ năm 2010; đây là liên kết gốc: github.com/kaeppler/droid-fu
esilver

3
Liên kết đó vẫn không hoạt động. Tôi đã viết một thư viện tương tự có tên là Android-ImageManager github.com/felipecsl/Android-ImageManager
Felipe Lima

9

Tôi đã dùng thử SoftReferences, chúng được khai thác quá mạnh trong Android mà tôi cảm thấy không có điểm nào sử dụng chúng


2
Đồng ý - SoftReferences được thu hồi rất nhanh trên các thiết bị tôi đã thử nghiệm
esilver

3
Google đã tự xác nhận rằng GC của Dalvik rất tích cực trong việc thu thập SoftReferences. Họ khuyên bạn nên sử dụng LruCachethay thế.
kaka

9

Như Thunder Rabbit đã đề xuất, ImageDoader là ứng dụng tốt nhất cho công việc. Tôi cũng tìm thấy một biến thể nhỏ của lớp tại:

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

Sự khác biệt chính giữa hai cái đó là ImageDoader sử dụng hệ thống bộ nhớ đệm Android và cái được sửa đổi sử dụng bộ nhớ trong và ngoài như bộ nhớ đệm, giữ hình ảnh được lưu trong bộ nhớ cache vô thời hạn hoặc cho đến khi người dùng xóa nó bằng tay. Tác giả cũng đề cập đến khả năng tương thích Android 2.1.


7

Đây là một bắt tốt của Joe. Ví dụ mã ở trên có hai vấn đề - một - đối tượng phản hồi không phải là một phiên bản của Bitmap (khi URL của tôi tham chiếu một jpg, như http: \ website.com \ image.jpg, đó là một

org.apache.harmony.luni.iternal.net.www.protatio.http.HttpURLConnectionImpl $ LimitedInputStream).

Thứ hai, như Joe chỉ ra, không có bộ đệm nào xảy ra mà không có bộ đệm phản hồi được cấu hình. Các nhà phát triển Android còn lại để cuộn bộ nhớ cache của riêng họ. Đây là một ví dụ để làm như vậy, nhưng nó chỉ lưu trữ trong bộ nhớ, đây thực sự không phải là giải pháp đầy đủ.

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

API bộ đệm URLConnection được mô tả ở đây:

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

Tôi vẫn nghĩ rằng đây là một giải pháp OK để đi theo con đường này - nhưng bạn vẫn phải viết một bộ đệm. Nghe có vẻ vui, nhưng tôi thích viết các tính năng hơn.


7

Có một mục đặc biệt trên phần đào tạo chính thức của Android về điều này: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

Phần này khá mới, nó không có ở đó khi câu hỏi được hỏi.

Giải pháp được đề xuất là sử dụng LruCache. Lớp đó đã được giới thiệu trên Honeycomb, nhưng nó cũng được bao gồm trong thư viện tương thích.

Bạn có thể khởi tạo LruCache bằng cách đặt số lượng tối đa hoặc các mục nhập và nó sẽ tự động sắp xếp chúng theo bạn và làm sạch chúng ít sử dụng hơn khi bạn vượt quá giới hạn. Ngoài ra, nó được sử dụng như một Bản đồ bình thường.

Mã mẫu từ trang chính thức:

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 trước đây là một lựa chọn tốt, nhưng không còn nữa, trích dẫn từ trang chính thức:

Lưu ý: Trước đây, việc triển khai bộ đệm bộ nhớ phổ biến là bộ đệm bitmap SoftReference hoặc WeakReference, tuy nhiên điều này không được khuyến khích. Bắt đầu từ Android 2.3 (API cấp 9), trình thu gom rác tích cực hơn với việc thu thập các tham chiếu mềm / yếu khiến chúng khá kém hiệu quả. Ngoài ra, trước Android 3.0 (API cấp 11), dữ liệu sao lưu của bitmap được lưu trữ trong bộ nhớ riêng không được phát hành theo cách có thể dự đoán được, có khả năng khiến ứng dụng vượt quá giới hạn bộ nhớ và sự cố.


3

Cân nhắc sử dụng thư viện Universal Image Loader của Sergey Tarasevich . Nó đi kèm với:

  • Tải hình ảnh đa luồng. Nó cho phép bạn có thể xác định kích thước nhóm luồng
  • Bộ nhớ đệm hình ảnh trong bộ nhớ, trên sytem tệp và thẻ SD của thiết bị.
  • Khả năng nghe tiến trình tải và tải sự kiện

Universal Image Loader cho phép quản lý bộ đệm chi tiết cho các hình ảnh được tải xuống, với các cấu hình bộ đệm sau:

  • UsingFreqLimitedMemoryCache: Bitmap ít được sử dụng nhất sẽ bị xóa khi vượt quá giới hạn kích thước bộ đệm.
  • LRULimitedMemoryCache: Bitmap ít được sử dụng gần đây nhất sẽ bị xóa khi vượt quá giới hạn kích thước bộ đệm.
  • FIFOLimitedMemoryCache: Quy tắc FIFO được sử dụng để xóa khi vượt quá giới hạn kích thước bộ đệm.
  • LargestLimitedMemoryCache: Bitmap lớn nhất bị xóa khi vượt quá giới hạn kích thước bộ đệm.
  • LimitedAgeMemoryCache: Đối tượng được lưu bị xóa khi tuổi của nó vượt quá giá trị được xác định .
  • WeakMemoryCache: Bộ nhớ cache chỉ có các tham chiếu yếu đến bitmap.

Một ví dụ sử dụng đơn giản:

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);

Ví dụ này sử dụng mặc định UsingFreqLimitedMemoryCache.


Khi được sử dụng mạnh mẽ, Universal Image Loader sẽ gây ra nhiều rò rỉ bộ nhớ. Tôi nghi ngờ điều này xảy ra bởi vì nó sử dụng các singletons trong mã (xem 'getInstance ()' trong ví dụ). Sau khi tải rất nhiều hình ảnh và sau đó xoay màn hình của tôi một vài lần, ứng dụng của tôi bị sập mọi lúc vì OutOfMemoryErrors trong UIL. Đó là một thư viện tuyệt vời nhưng đó là một thực tế nổi tiếng mà bạn KHÔNG BAO GIỜ nên sử dụng singletons, đặc biệt là không có trong Android ...
Geert Bellemans

1
SỬ DỤNG singletons khi bạn biết cách! :)
Renetik

3

Điều thực sự hiệu quả với tôi là thiết lập FeedbackCache trên lớp Main của tôi:

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);

khi tải bitmap.

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


có thể sử dụng lrucache khi kết hợp với omepresponsecache
iOSAndroidWindowsMobileAppsDev


1

Tôi đã vật lộn với điều này một thời gian; các câu trả lời sử dụng SoftReferences sẽ mất dữ liệu của họ quá nhanh. Các câu trả lời gợi ý việc tạo một RequestCache quá lộn xộn, cộng với tôi không bao giờ có thể tìm thấy một ví dụ đầy đủ.

Nhưng ImageDoader.java hoạt động tuyệt vời đối với tôi. Nó sử dụng HashMap cho đến khi đạt được dung lượng hoặc cho đến khi hết thời gian thanh lọc, sau đó mọi thứ được chuyển sang SoftReference, do đó sử dụng tốt nhất cả hai thế giới.



0

Ngay cả câu trả lời sau đó, nhưng tôi đã viết Trình quản lý hình ảnh Android xử lý bộ nhớ đệm trong suốt (bộ nhớ và đĩa). Mã này có trên Github https://github.com/felipecsl/Android-ImageManager


1
Tôi đã thêm nó vào ListView và dường như nó không xử lý tốt lắm. Có một số triển khai đặc biệt cho ListViews?

0

Cuối câu trả lời, nhưng tôi figured tôi nên thêm một liên kết đến trang web của tôi bởi vì tôi đã viết một hướng dẫn làm thế nào để thực hiện một bộ nhớ cache hình ảnh cho android: http://squarewolf.nl/2010/11/android-image-cache/ Cập nhật: các trang đã được ngoại tuyến vì nguồn đã lỗi thời. Tôi tham gia @elenasys trong lời khuyên của cô ấy để sử dụng Ignition .

Vì vậy, với tất cả những người vấp phải câu hỏi này và chưa tìm ra giải pháp: hy vọng bạn thích! = D


0

Trả lời muộn nhưng tôi nghĩ thư viện này sẽ giúp ích rất nhiều cho hình ảnh lưu trữ: https://github.com/crypticminds/ColdStorage .

Chỉ cần chú thích ImageView bằng @LoadCache (R.id.id_of_my_image_view, "URL_to_downlaod_image_from) và bạn sẽ phải tải xuống hình ảnh và tải hình ảnh vào chế độ xem hình ảnh. Bạn cũng có thể chỉ định hình ảnh giữ chỗ và tải hình ảnh.

Tài liệu chi tiết của chú thích có mặt tại đây: - https://github.com/crypticminds/ColdStorage/wiki/@LoadImage-annotation

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.