public class LruCache<K, V> {
private final LinkedHashMap<K, V> map;
...
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
...
}
//获取当前进程的可用内存(单位KB)
int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);
int memoryCacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(memoryCacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
/*
* Attempt to create a value. This may take a long time, and the map
* may be different when create() returns. If a conflicting value was
* added to the map while create() was working, we leave that value in
* the map and release the created value.
*/
V createdValue = create(key);
if (createdValue == null) {
return null;
}
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
private String getKeyFromUrl(String url) {
String key;
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(url.getBytes());
byte[] m = messageDigest.digest();
return getString(m);
} catch (NoSuchAlgorithmException e) {
key = String.valueOf(url.hashCode());
}
return key;
}
private static String getString(byte[] b){
StringBuffer sb = new StringBuffer();
for(int i = 0; i < b.length; i ++){
sb.append(b[i]);
}
return sb.toString();
}
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
trimToSize(maxSize);
return previous;
}
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
this.directory = directory;
this.appVersion = appVersion;
this.journalFile = new File(directory, JOURNAL_FILE);
this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
this.valueCount = valueCount;
this.maxSize = maxSize;
}
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
throws IOException {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
if (valueCount <= 0) {
throw new IllegalArgumentException("valueCount <= 0");
}
// prefer to pick up where we left off
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
if (cache.journalFile.exists()) {
try {
cache.readJournal();
cache.processJournal();
cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true),
IO_BUFFER_SIZE);
return cache;
} catch (IOException journalIsCorrupt) {
// System.logW("DiskLruCache " + directory + " is corrupt: "
// + journalIsCorrupt.getMessage() + ", removing");
cache.delete();
}
}
// create a new empty cache
directory.mkdirs();
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
cache.rebuildJournal();
return cache;
}
File diskCacheDir= getAppCacheDir(mContext, "images");
if (!diskCacheDir.exists()) {
diskCacheDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE);
public static File getAppCacheDir(Context context, String dirName) {
String cacheDirString;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
cacheDirString = context.getExternalCacheDir().getPath();
} else {
cacheDirString = context.getCacheDir().getPath();
}
return new File(cacheDirString + File.separator + dirName);
}
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0); //参数为索引,由于我们创建时指定一个节点只有一个缓存对象,所以传入0即可
}
//getStream为我们自定义的方法,它通过URL获取输入流并写入outputStream,具体实现后文会给出
if (getStreamFromUrl(url, outputStream)) {
editor.commit();
} else {
//返回false表示写入outputStream未成功,因此调用abort方法回退整个操作
editor.abort();
}
mDiskLruCache.flush(); //将内存中的操作记录同步到日志文件中
public boolean getStreamFromUrl(String urlString, OutputStream outputStream) {
HttpURLConnection urlCOnnection = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
bis = new BufferedInputStream(urlConnection.getInputStream(), BUF_SIZE);
int byteRead;
while ((byteRead = bis.read()) != -1) {
bos.write(byteRead);
}
return true;
}catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
//HttpUtils为一个自定义工具类
HttpUtils.close(bis);
HttpUtils.close(bos);
}
return false;
}
public synchronized Snapshot get(String key) throws IOException {
checkNotClosed();
validateKey(key);
Entry entry = lruEntries.get(key);
if (entry == null) {
return null;
}
if (!entry.readable) {
return null;
}
/*
* Open all streams eagerly to guarantee that we see a single published
* snapshot. If we opened streams lazily then the streams could come
* from different edits.
*/
InputStream[] ins = new InputStream[valueCount];19 ...
return new Snapshot(key, entry.sequenceNumber, ins);
}
Bitmap bitmap = null;
String key = getKeyFromUrl(url);
DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
if (snapShot != null) {
FileInputStream fileInputStream = (FileInputStream) snapShot.getInputStream(0); //参数表示索引,同之前的newOutputStream一样
FileDescriptor fileDescriptor = fileInputStream.getFD();
bitmap = decodeSampledBitmapFromFD(fileDescriptor, dstWidth, dstHeight);
if (bitmap != null) {
addBitmapToMemoryCache(key, bitmap);
}
}
public Bitmap decodeSampledBitmapFromFD(FileDescriptor fd, int dstWidth, int dstHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(fd, null, options);
//calInSampleSize方法的实现请见“Android开发之高效加载Bitmap”这篇博文
options.inSampleSize = calInSampleSize(options, dstWidth, dstHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFileDescriptor(fd, null, options);
}
public Bitmap loadBitmap(String url, int dstWidth, int dstHeight) {
Bitmap bitmap = loadFromMemory(url);
if (bitmap != null) {
return bitmap;
}
//内存缓存中不存在相应图片
try {
bitmap = loadFromDisk(url, dstWidth, dstHeight);
if (bitmap != null) {
return bitmap;
}
//磁盘缓存中也不存在相应图片
bitmap = loadFromNet(url, dstWidth, dstHeight);
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
public void displayImage(String url, ImageView imageView, int dstWidth, int widthHeight) {
imageView.setTag(IMG_URL, url);
Bitmap bitmap = loadFromMemory(url);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
return;
}
Runnable loadBitmapTask = new Runnable() {
@Override
public void run() {
Bitmap bitmap = loadBitmap(url, dstWidth, dstHeigth);
if (bitmap != null) {
//Result是我们自定义的类,封装了返回的Bitmap以及它的URL和作为它的容器的ImageView
Result result = new Result(bitmap, url, imageView);
//mMainHandler为主线程中创建的Handler
Message msg = mMainHandler.obtainMessage(MESSAGE_SEND_RESULT, result);
msg.sendToTarget();
}
}
};
threadPoolExecutor.execute(loadBitmapTask);
}
private static final int CORE_POOL_SIZE = CPU_COUNT + 1; //corePoolSize为CPU数加1
private static final int MAX_POOL_SIZE = 2 * CPU_COUNT + 1; //maxPoolSize为2倍的CPU数加1
private static final long KEEP_ALIVE = 5L; //存活时间为5s
public static final Executor threadPoolExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
private Handler mMainHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
Result result = (Result) msg.what;
ImageView imageView = result.imageView;
String url = (String) imageView.getTag(IMG_URL);
if (url.equals(result.url)) {
imageView.setImageBitmap(result.bitmap);
} else {
Log.w(TAG, "The url associated with imageView has changed");
}
};
};
private LruCache<String, Bitmap> mMemoryCache;
private DiskLruCache mDiskLruCache;
private ImageLoader(Context context) {
mContext = context.getApplicationContext();
int maxMemory = (int) (Runtime.getRuntime().maxMemory() /1024);
int cacheSize = maxMemory / 8;
mMemorySize = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeof(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
File diskCacheDir = getAppCacheDir(mContext, "images");
if (!diskCacheDir.exists()) {
diskCacheDir.mkdirs();
}
if (diskCacheDir.getUsableSpace() > DISK_CACHE_SIZE) {
//剩余空间大于我们指定的磁盘缓存大小
try {
mDiskLruCache = DiskLruCache.open(diskCacheDir, 1, 1, DISK_CACHE_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void addToMemoryCache(String key, Bitmap bitmap) {
if (getFromMemoryCache(key) == null) {
//不存在时才添加
mMemoryCache.put(key, bitmap);
}
}
private Bitmap getFromMemoryCache(String key) {
return mMemoryCache.get(key);
}
private loadFromDiskCache(String url, int dstWidth, int dstHeight) throws IOException {
if (Looper.myLooper() == Looper.getMainLooper()) {
//当前运行在主线程,报错
Log.w(TAG, "should not Bitmap in main thread");
}
if (mDiskLruCache == null) {
return null;
}
Bitmap bitmap = null;
String key = getKeyFromUrl(url);
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key);
if (snapshot != null) {
FileInputStream fileInputStream = (FileInputStream) snapshot.getInputStream(0);
FileDescriptor fileDescriptor = fileInputStream.getFD();
bitmap = decodeSampledBitmapFromFD(fileDescriptor, dstWidth, dstHeight);
if (bitmap != null) {
addToMemoryCache(key, bitmap);
}
}
return bitmap;
}
private Bitmap loadFromNet(String url, int dstWidth, int dstHeight) throws IOException {
if (Looper.myLooper() == Looper.getMainLooper()) {
throw new RuntimeException("Do not load Bitmap in main thread.");
}
if (mDiskLruCache == null) {
return null;
}
String key = getKeyFromUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if (editor != null) {
OutputStream outputStream = editor.newOutputStream(0);
if (getStreamFromUrl(url, outputStream)) {
editor.commit();
} else {
editor.abort();
}
mDiskLruCache.flush();
}
return loadFromDiskCache(url, dstWidth, dstHeight);
}
//加载图片前的时间点 long beforeTime = System.currentTimeMillis(); //加载图片完成的时间点 long afterTime = System.currentTimeMillis(); //total为图片的总数,averTime为加载每张图片所需的平均时间 int averTime = (int) ((afterTime - beforeTime) / total)
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有