2010-06-21 45 views
11

Tôi đang triển khai hệ thống bộ nhớ cache hình ảnh để lưu vào bộ nhớ cache hình ảnh đã tải xuống.Android: Chiến lược bộ nhớ cache hình ảnh và bộ nhớ cache kích thước

Chiến lược của tôi dựa trên bộ nhớ cache hai cấp: Cấp bộ nhớ và mức đĩa.

Lớp học của tôi rất giống với lớp được sử dụng trong droidfu project

ảnh tải về của tôi được đưa vào một hashmap và Objet Bitmap được bọc bên trong một đối tượng SoftRererence. Ngoài ra mỗi hình ảnh được lưu vĩnh viễn vào đĩa. Nếu không tìm thấy hình ảnh được yêu cầu vào Hashmap<String,SoftReference<Bitmap>>, nó sẽ được tìm kiếm trên đĩa, được đọc và sau đó được đẩy trở lại vào băm. Nếu không, hình ảnh sẽ là được tải xuống từ mạng. Vì tôi lưu trữ các hình ảnh vào momery thiết bị phisical, tôi đã thêm một tấm séc trị bảo tồn không gian thiết bị và ở lại dưới một 1M không gian chiếm đóng:

private void checkCacheUsage() { 

     long size = 0; 
     final File[] fileList = new File(mCacheDirPath).listFiles(); 
     Arrays.sort(fileList, new Comparator<File>() { 
      public int compare(File f1, File f2) { 
       return Long.valueOf(f2.lastModified()).compareTo(
         f1.lastModified()); 
      } 
     }); 
     for (File file : fileList) { 
      size += file.length(); 
      if (size > MAX_DISK_CACHE_SIZE) { 
       file.delete(); 
       Log.d(ImageCache.class.getSimpleName(), 
         "checkCacheUsage: Size exceeded " + size + "(" 
           + MAX_DISK_CACHE_SIZE + ") wiping older file {"+file.toString()+"}"); 
      } 
     } 

    } 

Phương pháp này được gọi là đôi khi afte một văn bản đĩa:

Random r = new Random(); 
     int ra = r.nextInt(10); 

     if (ra % 2 == 0){ 
      checkCacheUsage(); 
     } 

Điều tôi muốn thêm là kiểm tra cùng kích thước HashMap để ngăn chặn nó phát triển quá nhiều. Một cái gì đó như thế này:

private synchronized void checkMemoryCacheUsage(){ 

      long size = 0; 

      for (SoftReference<Bitmap> a : cache.values()) { 

       final Bitmap b = a.get(); 

       if (b != null && ! b.isRecycled()){ 
        size += b.getRowBytes() * b.getHeight(); 
       } 

       if (size > MAX_MEMORY_SIZE){ 
        //Remove some elements from the cache 
       } 

      } 

      Log.d(ImageCache.class.getSimpleName(), 
        "checkMemoryCacheUsage: " + size + " in memory"); 

    } 

Câu hỏi của tôi là: gì có thể là một giá trị MAX_MEMORY_SIZE phải không? Ngoài ra, đó có phải là cách tiếp cận tốt không? Câu trả lời hay cũng có thể là: "Đừng làm vậy! SoftReference đã đủ rồi"

+0

Bạn cũng có thể xem xét API này http: //docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/cache/CacheBuilder.html – carfield

Trả lời

8

Đừng làm điều đó! SoftReference đã đủ rồi! Trên thực tế SoftReference được thiết kế để thực hiện chính xác những gì bạn cần. Đôi khi SoftReference không thực hiện những gì bạn cần. Sau đó, bạn chỉ cần thoát khỏi SoftReference và viết logic quản lý bộ nhớ của riêng bạn. Nhưng theo như bạn sử dụng SoftReference, bạn không nên lo lắng về mức tiêu thụ bộ nhớ, SoftReference thực hiện nó cho bạn.

+0

Android triển khai các tham chiếu mềm theo cách tạo ra nó không phù hợp với loại bộ nhớ đệm này. Xem báo cáo lỗi này để biết thêm thông tin: http://code.google.com/p/android/issues/detail?id=20015&can=1&q=softReference&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars. Các hình ảnh sẽ bị xóa khỏi bộ nhớ tại thời điểm chúng chỉ có thể truy cập thông qua SoftReference. Nhóm Google khuyên bạn nên sử dụng bộ nhớ cache LRU. Vấn đề ở đây là để xác định kích thước tối đa của bộ đệm. – Janusz

+0

@Janusz, Điều đó rất đúng. Nhưng vì không có bộ nhớ cache LRU thực hiện mà mọi người mới bắt đầu có thể lấy và sử dụng lại họ phải bắt đầu với SoftReference. Nó không hoàn hảo (tôi biết vấn đề bạn đang nói đến) nhưng nó đủ tốt để bắt đầu. – Fedor

+0

Tôi không nghĩ rằng nó đủ goog để bắt đầu. Với tốc độ bộ nhớ được giải phóng tại thời điểm tham chiếu mềm là vô ích và gây ra rất nhiều nhầm lẫn. Hoàn toàn không có gì để đạt được bằng cách sử dụng chúng. – Janusz

1

Tôi đang sử dụng một phần ba bộ nhớ cache cho bộ nhớ cache hình ảnh.

int memoryInMB = activityManager.getMemoryClass(); 
long totalAppHeap = memoryInMB * 1024 * 1024; 
int runtimeCacheLimit = (int)totalAppHeap/3; 

Nhân tiện, về tham chiếu mềm, trong tham chiếu Android Soft không hoạt động như bạn mong đợi. Có một vấn đề nền tảng mà tài liệu tham khảo mềm được thu thập quá sớm, ngay cả khi có rất nhiều bộ nhớ miễn phí.

Kiểm tra http://code-gotcha.blogspot.com/2011/09/softreference.html

0

Tôi đã nhìn vào cơ chế bộ nhớ đệm khác nhau cho bitmap thu nhỏ của tôi, cả hai bộ nhớ và bộ nhớ cache đĩa ví dụ. Các ví dụ phức tạp cho nhu cầu của tôi, vì vậy tôi đã tạo bộ nhớ cache bitmap của riêng mình bằng LruCache. Bạn có thể nhìn vào một mã ví dụ làm việc here hoặc sử dụng mã này:

bộ nhớ Cache:

public class Cache { 
    private static LruCache<Integer, Bitmap> bitmaps = new BitmapLruCache(); 

    public static Bitmap get(int drawableId){ 
     Bitmap bitmap = bitmaps.get(drawableId); 
     if(bitmap != null){ 
      return bitmap; 
     } else { 
      bitmap = SpriteUtil.createScaledBitmap(drawableId); 
      bitmaps.put(drawableId, bitmap); 
      return bitmap; 
     } 
    } 
} 

BitmapLruCache:

public class BitmapLruCache extends LruCache<Integer, Bitmap> { 
    private final static int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 
    private final static int cacheSize = maxMemory/2; 

    public BitmapLruCache() { 
     super(cacheSize); 
    } 

    @Override 
    protected int sizeOf(Integer key, Bitmap bitmap) { 
     // The cache size will be measured in kilobytes rather than number of items. 
     return bitmap.getRowBytes() * bitmap.getHeight()/1024; 
    } 
} 
Các vấn đề liên quan