Android每次加载图片很浪费时间。所以设计了一个图片缓存技术来解决每次android手机加载图片的问题
内存的读取速度是最快的,然后是文件的读取速度,最后是网络资源的读取
既然内存的读取时间最快,我们好好利用内存资源。将内存再分两层缓存
强引用缓存不会轻易被回收,来保存常用数据,不常用的资源放入软引用缓存中。
对于硬引用和软引用的介绍:
⑴强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
⑵软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存
1,对于强引用和软引用的使用,我们首先去强引用缓存中去找图片资源,当没有发现时,就去软引用缓存中。当强引用的超额时,将最后使用的资源放入软引用缓存中,使用到软引用的资源时 ,则将资源重新放回强引用缓存池中。
2,内存缓存池中找不到,就去文件中查找,
3,再找不到就只好去网络上下载了,下载到以后,分别将资源放入文件缓存和内存缓存中
Android对于InputStream流有个小bug在慢速网络的情况下可能产生中断,可以考虑重写FilterInputStream处理skip方法来解决这个bug。 BitmapFactory类的decodeStream方法在网络超时或较慢的时候无法获取完整的数据,这里我 们通过继承FilterInputStream类的skip方法来强制实现flush流中的数据,主要原理就是检查是否到文件末端,告诉http类是否继续。
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int b = read();
if (b < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
主界面读取图片
- public class MainActivity extends Activity {
-
- private ImageMemoryCache memoryCache;
- private ImageFileCache fileCache;
- private ImageView imageView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- memoryCache=new ImageMemoryCache(this);
- fileCache=new ImageFileCache();
- imageView=(ImageView) findViewById(R.id.img);
- Bitmap b=getBitmap("http://f.hiphotos.baidu.com/album/w%3D2048/sign=7aa167f79f2f07085f052d00dd1cb999/472309f7905298228f794c7bd6ca7bcb0b46d4c4.jpg");
- imageView.setImageBitmap(b);
-
-
-
- }
-
- public Bitmap getBitmap(String url) {
-
- Bitmap result = memoryCache.getBitmapFromCache(url);
- if (result == null) {
-
- result = fileCache.getImage(url);
- if (result == null) {
-
- result = ImageGetFromHttp.downloadBitmap(url);
- if (result != null) {
- fileCache.saveBitmap(result, url);
- memoryCache.addBitmapToCache(url, result);
- }
- } else {
-
- memoryCache.addBitmapToCache(url, result);
- }
- }
- return result;
- }
-
- }
内存中读取
- public class ImageMemoryCache {
-
-
-
-
- private static final int SOFT_CACHE_SIZE = 15;
- private static LruCache<String, Bitmap> mLruCache;
- private static LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;
-
- public ImageMemoryCache(Context context) {
- int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
- int cacheSize = 1024 * 1024 * memClass / 4;
- mLruCache = new LruCache<String, Bitmap>(cacheSize) {
- @Override
- protected int sizeOf(String key, Bitmap value) {
- if (value != null)
- return value.getRowBytes() * value.getHeight();
- else
- return 0;
- }
-
- @Override
- protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
- if (oldValue != null)
-
- mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
- }
- };
- mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(SOFT_CACHE_SIZE, 0.75f, true) {
- private static final long serialVersionUID = 6040103833179403725L;
- @Override
- protected boolean removeEldestEntry(Entry<String, SoftReference<Bitmap>> eldest) {
- if (size() > SOFT_CACHE_SIZE){
- return true;
- }
- return false;
- }
- };
- }
-
-
-
-
- public Bitmap getBitmapFromCache(String url) {
- Bitmap bitmap;
-
- synchronized (mLruCache) {
- bitmap = mLruCache.get(url);
- if (bitmap != null) {
-
- mLruCache.remove(url);
- mLruCache.put(url, bitmap);
- return bitmap;
- }
- }
-
- synchronized (mSoftCache) {
- SoftReference<Bitmap> bitmapReference = mSoftCache.get(url);
- if (bitmapReference != null) {
- bitmap = bitmapReference.get();
- if (bitmap != null) {
-
- mLruCache.put(url, bitmap);
- mSoftCache.remove(url);
- return bitmap;
- } else {
- mSoftCache.remove(url);
- }
- }
- }
- return null;
- }
-
-
-
-
- public void addBitmapToCache(String url, Bitmap bitmap) {
- if (bitmap != null) {
- synchronized (mLruCache) {
- mLruCache.put(url, bitmap);
- }
- }
- }
-
- public void clearCache() {
- mSoftCache.clear();
- }
- }
网络下载图片
- public class ImageGetFromHttp {
- private static final String LOG_TAG = "ImageGetFromHttp";
-
- public static Bitmap downloadBitmap(String url) {
- final HttpClient client = new DefaultHttpClient();
- final HttpGet getRequest = new HttpGet(url);
-
- try {
- HttpResponse response = client.execute(getRequest);
- final int statusCode = response.getStatusLine().getStatusCode();
- if (statusCode != HttpStatus.SC_OK) {
- Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);
- return null;
- }
-
- final HttpEntity entity = response.getEntity();
- if (entity != null) {
- InputStream inputStream = null;
- try {
- inputStream = entity.getContent();
- FilterInputStream fit = new FlushedInputStream(inputStream);
- return BitmapFactory.decodeStream(fit);
- } finally {
- if (inputStream != null) {
- inputStream.close();
- inputStream = null;
- }
- entity.consumeContent();
- }
- }
- } catch (IOException e) {
- getRequest.abort();
- Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
- } catch (IllegalStateException e) {
- getRequest.abort();
- Log.w(LOG_TAG, "Incorrect URL: " + url);
- } catch (Exception e) {
- getRequest.abort();
- Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
- } finally {
- client.getConnectionManager().shutdown();
- }
- return null;
- }
-
-
-
-
- static class FlushedInputStream extends FilterInputStream {
- public FlushedInputStream(InputStream inputStream) {
- super(inputStream);
- }
-
- @Override
- public long skip(long n) throws IOException {
- long totalBytesSkipped = 0L;
- while (totalBytesSkipped < n) {
- long bytesSkipped = in.skip(n - totalBytesSkipped);
- if (bytesSkipped == 0L) {
- int b = read();
- if (b < 0) {
- break;
- } else {
- bytesSkipped = 1;
- }
- }
- totalBytesSkipped += bytesSkipped;
- }
- return totalBytesSkipped;
- }
- }
- }
权限
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />