全面解析Android的开源图片框架Universal-Image-Loader

2019-12-10 18:34:04丽君

这个类是继承LimitedDiscCache,除了两个构造函数之外,还重写了getSize()方法,返回文件的大小,接下来我们就来看看LimitedDiscCache

/******************************************************************************* 
 * Copyright 2011-2013 Sergey Tarasevich 
 * 
 * Licensed 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.easck.com/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. 
 *******************************************************************************/ 
package com.nostra13.universalimageloader.cache.disc; 
 
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator; 
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory; 
 
import java.io.File; 
import java.util.Collections; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Map.Entry; 
import java.util.Set; 
import java.util.concurrent.atomic.AtomicInteger; 
 
/** 
 * Abstract disc cache limited by some parameter. If cache exceeds specified limit then file with the most oldest last 
 * usage date will be deleted. 
 * 
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 
 * @see BaseDiscCache 
 * @see FileNameGenerator 
 * @since 1.0.0 
 */ 
public abstract class LimitedDiscCache extends BaseDiscCache { 
 
 private static final int INVALID_SIZE = -1; 
 
 //记录缓存文件的大小 
 private final AtomicInteger cacheSize; 
 //缓存文件的最大值 
 private final int sizeLimit; 
 private final Map<File, Long> lastUsageDates = Collections.synchronizedMap(new HashMap<File, Long>()); 
 
 /** 
  * @param cacheDir Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
  *     needed for right cache limit work. 
  * @param sizeLimit Cache limit value. If cache exceeds this limit then file with the most oldest last usage date 
  *     will be deleted. 
  */ 
 public LimitedDiscCache(File cacheDir, int sizeLimit) { 
  this(cacheDir, DefaultConfigurationFactory.createFileNameGenerator(), sizeLimit); 
 } 
 
 /** 
  * @param cacheDir   Directory for file caching. <b>Important:</b> Specify separate folder for cached files. It's 
  *       needed for right cache limit work. 
  * @param fileNameGenerator Name generator for cached files 
  * @param sizeLimit   Cache limit value. If cache exceeds this limit then file with the most oldest last usage date 
  *       will be deleted. 
  */ 
 public LimitedDiscCache(File cacheDir, FileNameGenerator fileNameGenerator, int sizeLimit) { 
  super(cacheDir, fileNameGenerator); 
  this.sizeLimit = sizeLimit; 
  cacheSize = new AtomicInteger(); 
  calculateCacheSizeAndFillUsageMap(); 
 } 
 
 /** 
  * 另开线程计算cacheDir里面文件的大小,并将文件和最后修改的毫秒数加入到Map中 
  */ 
 private void calculateCacheSizeAndFillUsageMap() { 
  new Thread(new Runnable() { 
   @Override 
   public void run() { 
    int size = 0; 
    File[] cachedFiles = cacheDir.listFiles(); 
    if (cachedFiles != null) { // rarely but it can happen, don't know why 
     for (File cachedFile : cachedFiles) { 
      //getSize()是一个抽象方法,子类自行实现getSize()的逻辑 
      size += getSize(cachedFile); 
      //将文件的最后修改时间加入到map中 
      lastUsageDates.put(cachedFile, cachedFile.lastModified()); 
     } 
     cacheSize.set(size); 
    } 
   } 
  }).start(); 
 } 
 
 /** 
  * 将文件添加到Map中,并计算缓存文件的大小是否超过了我们设置的最大缓存数 
  * 超过了就删除最先加入的那个文件 
  */ 
 @Override 
 public void put(String key, File file) { 
  //要加入文件的大小 
  int valueSize = getSize(file); 
   
  //获取当前缓存文件大小总数 
  int curCacheSize = cacheSize.get(); 
  //判断是否超过设定的最大缓存值 
  while (curCacheSize + valueSize > sizeLimit) { 
   int freedSize = removeNext(); 
   if (freedSize == INVALID_SIZE) break; // cache is empty (have nothing to delete) 
   curCacheSize = cacheSize.addAndGet(-freedSize); 
  } 
  cacheSize.addAndGet(valueSize); 
 
  Long currentTime = System.currentTimeMillis(); 
  file.setLastModified(currentTime); 
  lastUsageDates.put(file, currentTime); 
 } 
 
 /** 
  * 根据key生成文件 
  */ 
 @Override 
 public File get(String key) { 
  File file = super.get(key); 
 
  Long currentTime = System.currentTimeMillis(); 
  file.setLastModified(currentTime); 
  lastUsageDates.put(file, currentTime); 
 
  return file; 
 } 
 
 /** 
  * 硬盘缓存的清理 
  */ 
 @Override 
 public void clear() { 
  lastUsageDates.clear(); 
  cacheSize.set(0); 
  super.clear(); 
 } 
 
  
 /** 
  * 获取最早加入的缓存文件,并将其删除 
  */ 
 private int removeNext() { 
  if (lastUsageDates.isEmpty()) { 
   return INVALID_SIZE; 
  } 
  Long oldestUsage = null; 
  File mostLongUsedFile = null; 
   
  Set<Entry<File, Long>> entries = lastUsageDates.entrySet(); 
  synchronized (lastUsageDates) { 
   for (Entry<File, Long> entry : entries) { 
    if (mostLongUsedFile == null) { 
     mostLongUsedFile = entry.getKey(); 
     oldestUsage = entry.getValue(); 
    } else { 
     Long lastValueUsage = entry.getValue(); 
     if (lastValueUsage < oldestUsage) { 
      oldestUsage = lastValueUsage; 
      mostLongUsedFile = entry.getKey(); 
     } 
    } 
   } 
  } 
 
  int fileSize = 0; 
  if (mostLongUsedFile != null) { 
   if (mostLongUsedFile.exists()) { 
    fileSize = getSize(mostLongUsedFile); 
    if (mostLongUsedFile.delete()) { 
     lastUsageDates.remove(mostLongUsedFile); 
    } 
   } else { 
    lastUsageDates.remove(mostLongUsedFile); 
   } 
  } 
  return fileSize; 
 } 
 
 /** 
  * 抽象方法,获取文件大小 
  * @param file 
  * @return 
  */ 
 protected abstract int getSize(File file); 
}