Android 内存+文件+网络三级缓存

来源:互联网 发布:海岛大亨5 mac 汉化 编辑:程序博客网 时间:2024/05/02 03:06
package com.panpass.main;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.os.Bundle;import android.os.Handler;import android.os.Message;/*  * 图片管理  * 异步获取图片,直接调用loadImage()函数,该函数自己判断是从缓存还是网络加载  * 同步获取图片,直接调用getBitmap()函数,该函数自己判断是从缓存还是网络加载  * 仅从本地获取图片,调用getBitmapFromNative()  * 仅从网络加载图片,调用getBitmapFromHttp()  *  */public class ImageManager {public static ImageManager im = null;private final static String TAG = "ImageManager";private ImageMemoryCache imageMemoryCache; // 内存缓存private ImageFileCache imageFileCache; // 文件缓存// 正在下载的image列表public static HashMap<String, Handler> ongoingTaskMap = new HashMap<String, Handler>();// 等待下载的image列表public static HashMap<String, Handler> waitingTaskMap = new HashMap<String, Handler>();// 同时下载图片的线程个数final static int MAX_DOWNLOAD_IMAGE_THREAD = 4;private final Handler downloadStatusHandler = new Handler() {public void handleMessage(Message msg) {startDownloadNext();}};public static ImageManager getInstance(Context mContext) {if (im == null) {synchronized (ImageManager.class) {if (im == null) {im = new ImageManager(mContext);}}}return im;}public ImageManager(Context mContext) {imageMemoryCache = new ImageMemoryCache();imageFileCache = new ImageFileCache(mContext);}/** * 获取图片,多线程的入口 */public void loadBitmap(String urlStr, Handler handler) {String url = urlStr.hashCode() + "";// 先从内存缓存中获取,取到直接加载Bitmap bitmap = getBitmapFromNative(urlStr);if (bitmap != null) {Message msg = Message.obtain();Bundle bundle = new Bundle();bundle.putString("url", url);msg.obj = bitmap;msg.setData(bundle);handler.sendMessage(msg);} else {downloadBmpOnNewThread(urlStr, handler);}}/** * 新起线程下载图片 */private void downloadBmpOnNewThread(final String urlStr,final Handler handler) {final String url = urlStr.hashCode() + "";if (ongoingTaskMap.size() >= MAX_DOWNLOAD_IMAGE_THREAD) {synchronized (waitingTaskMap) {waitingTaskMap.put(url, handler);}} else {synchronized (ongoingTaskMap) {ongoingTaskMap.put(url, handler);}new Thread() {public void run() {Bitmap bmp = getBitmapFromHttp(urlStr);// 不论下载是否成功,都从下载队列中移除,再由业务逻辑判断是否重新下载// 下载图片使用了httpClientRequest,本身已经带了重连机制synchronized (ongoingTaskMap) {ongoingTaskMap.remove(url);}if (downloadStatusHandler != null) {downloadStatusHandler.sendEmptyMessage(0);}Message msg = Message.obtain();msg.obj = bmp;Bundle bundle = new Bundle();bundle.putString("url", url);msg.setData(bundle);if (handler != null) {handler.sendMessage(msg);}}}.start();}}/** * 依次从内存,缓存文件,网络上加载单个bitmap,不考虑线程的问题 */public Bitmap getBitmap(String urlStr) {String url = urlStr.hashCode() + "";// 从内存缓存中获取图片Bitmap bitmap = imageMemoryCache.getBitmapFromMemory(url);if (bitmap == null) {// 文件缓存中获取bitmap = imageFileCache.getImageFromFile(url);if (bitmap != null) {// 添加到内存缓存imageMemoryCache.addBitmapToMemory(url, bitmap);} else {// 从网络获取bitmap = getBitmapFromHttp(urlStr);}}return bitmap;}/** * 从内存或者缓存文件中获取bitmap */public Bitmap getBitmapFromNative(String urlStr) {String url = urlStr.hashCode() + "";Bitmap bitmap = null;bitmap = imageMemoryCache.getBitmapFromMemory(url);if (bitmap == null) {bitmap = imageFileCache.getImageFromFile(url);if (bitmap != null) {// 添加到内存缓存imageMemoryCache.addBitmapToMemory(url, bitmap);}}return bitmap;}/** * 通过网络下载图片,与线程无关 */public Bitmap getBitmapFromHttp(String urlStr) {String url = urlStr.hashCode() + "";Bitmap bmp = null;try {byte[] tmpPicByte = getImageBytes(urlStr);if (tmpPicByte != null) {bmp = BitmapFactory.decodeByteArray(tmpPicByte, 0,tmpPicByte.length);}tmpPicByte = null;} catch (Exception e) {e.printStackTrace();}if (bmp != null) {// 添加到文件缓存imageFileCache.saveBitmapToFile(bmp, url);// 添加到内存缓存imageMemoryCache.addBitmapToMemory(url, bmp);}return bmp;}/** * 下载链接的图片资源 *  * @param url *  * @return 图片 */public byte[] getImageBytes(String urlStr) {if (urlStr != null && !"".equals(urlStr)) {HttpGet get = new HttpGet(urlStr);get.addHeader("Accept-Encoding", "indentity");HttpClient client = new DefaultHttpClient();HttpResponse response = null;try {response = client.execute(get);if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {InputStream is = response.getEntity().getContent();ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buf = new byte[1024];int len = -1;while ((len = is.read(buf)) != -1) {baos.write(buf, 0, len);}return baos.toByteArray();}} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}return null;}/** * 取出等待队列第一个任务,开始下载 */private void startDownloadNext() {synchronized (waitingTaskMap) {Iterator<Entry<String, Handler>> iter = waitingTaskMap.entrySet().iterator();if (iter.hasNext()) {Map.Entry<String, Handler> entry = (Map.Entry<String, Handler>) iter.next();if (entry != null) {waitingTaskMap.remove(entry.getKey());downloadBmpOnNewThread((String) entry.getKey(),(Handler) entry.getValue());}}}}/** * 图片变为圆角 *  * @param bitmap *            :传入的bitmap * @param pixels *            :圆角的度数,值越大,圆角越大 * @return bitmap:加入圆角的bitmap */public static Bitmap toRoundCorner(Bitmap bitmap, int pixels) {if (bitmap == null)return null;Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Config.ARGB_8888);Canvas canvas = new Canvas(output);final int color = 0xff424242;final Paint paint = new Paint();final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());final RectF rectF = new RectF(rect);final float roundPx = pixels;paint.setAntiAlias(true);canvas.drawARGB(0, 0, 0, 0);paint.setColor(color);canvas.drawRoundRect(rectF, roundPx, roundPx, paint);// paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));canvas.drawBitmap(bitmap, rect, rect, paint);return output;}}
package com.panpass.main;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;public class ImageFileCache {<span style="white-space:pre"></span>private File cacheDir;<span style="white-space:pre"></span>public ImageFileCache(Context context) {<span style="white-space:pre"></span>// 如果有SD卡则在SD卡中建一个LazyList的目录存放缓存的图片<span style="white-space:pre"></span>// 没有SD卡就放在系统的缓存目录中<span style="white-space:pre"></span>if (android.os.Environment.getExternalStorageState().equals(<span style="white-space:pre"></span>android.os.Environment.MEDIA_MOUNTED))<span style="white-space:pre"></span>cacheDir = new File(<span style="white-space:pre"></span>android.os.Environment.getExternalStorageDirectory(),<span style="white-space:pre"></span>"LazyList");<span style="white-space:pre"></span>else<span style="white-space:pre"></span>cacheDir = context.getCacheDir();<span style="white-space:pre"></span>if (!cacheDir.exists())<span style="white-space:pre"></span>cacheDir.mkdirs();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public Bitmap getImageFromFile(String url) {<span style="white-space:pre"></span>// 将url的hashCode作为缓存的文件名<span style="white-space:pre"></span>// Another possible solution<span style="white-space:pre"></span>// String filename = URLEncoder.encode(url);<span style="white-space:pre"></span>File f = new File(cacheDir, url);<span style="white-space:pre"></span>if(f.exists()){<span style="white-space:pre"></span>return BitmapFactory.decodeFile(f.getAbsolutePath());<span style="white-space:pre"></span>}<span style="white-space:pre"></span>return null;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void saveBitmapToFile(Bitmap bm ,String url) {<span style="white-space:pre"></span>File file=new File(cacheDir,url);//将要保存图片的路径<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));<span style="white-space:pre"></span>bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);<span style="white-space:pre"></span>bos.flush();<span style="white-space:pre"></span>bos.close();<span style="white-space:pre"></span>} catch (IOException e) {<span style="white-space:pre"></span>e.printStackTrace();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void clear() {<span style="white-space:pre"></span>File[] files = cacheDir.listFiles();<span style="white-space:pre"></span>if (files == null)<span style="white-space:pre"></span>return;<span style="white-space:pre"></span>for (File f : files)<span style="white-space:pre"></span>f.delete();<span style="white-space:pre"></span>}}
package com.panpass.main;import java.util.Collections;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.Map;import java.util.Map.Entry;import android.graphics.Bitmap;import android.util.Log;public class ImageMemoryCache {<span style="white-space:pre"></span>private static final String TAG = "MemoryCache";<span style="white-space:pre"></span>/**<span style="white-space:pre"></span> * 放入缓存时是个同步操作 LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最 近使用次数由少到多排列,<span style="white-space:pre"></span> * 即LRU。<span style="white-space:pre"></span> * 这样的好处是如果要将缓存中的元素替换,则先遍历出最近最少使用的元素来替换以提高效率<span style="white-space:pre"></span> */<span style="white-space:pre"></span>private Map<String, Bitmap> cache = Collections<span style="white-space:pre"></span>.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));<span style="white-space:pre"></span>// 缓存中图片所占用的字节,初始0,将通过此变量严格控制缓存所占用的堆内存<span style="white-space:pre"></span>private long size = 0;// current allocated size<span style="white-space:pre"></span>// 缓存只能占用的最大堆内存<span style="white-space:pre"></span>private long limit = 1000000;// max memory in bytes<span style="white-space:pre"></span>public ImageMemoryCache() {<span style="white-space:pre"></span>// use 25% of available heap size<span style="white-space:pre"></span>setLimit(Runtime.getRuntime().maxMemory() / 4);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void setLimit(long new_limit) {<span style="white-space:pre"></span>limit = new_limit;<span style="white-space:pre"></span>Log.i(TAG, "MemoryCache will use up to " + limit / 1024. / 1024. + "MB");<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public Bitmap getBitmapFromMemory(String id) {<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>if (!cache.containsKey(id))<span style="white-space:pre"></span>return null;<span style="white-space:pre"></span>return cache.get(id);<span style="white-space:pre"></span>} catch (NullPointerException ex) {<span style="white-space:pre"></span>return null;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void addBitmapToMemory(String id, Bitmap bitmap) {<span style="white-space:pre"></span>try {<span style="white-space:pre"></span>if (cache.containsKey(id))<span style="white-space:pre"></span>size -= getSizeInBytes(cache.get(id));<span style="white-space:pre"></span>cache.put(id, bitmap);<span style="white-space:pre"></span>size += getSizeInBytes(bitmap);<span style="white-space:pre"></span>checkSize();<span style="white-space:pre"></span>} catch (Throwable th) {<span style="white-space:pre"></span>th.printStackTrace();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>/**<span style="white-space:pre"></span> * 严格控制堆内存,如果超过将首先替换最近最少使用的那个图片缓存<span style="white-space:pre"></span> * <span style="white-space:pre"></span> */<span style="white-space:pre"></span>private void checkSize() {<span style="white-space:pre"></span>Log.i(TAG, "cache size=" + size + " length=" + cache.size());<span style="white-space:pre"></span>if (size > limit) {<span style="white-space:pre"></span>// 先遍历最近最少使用的元素<span style="white-space:pre"></span>Iterator<Entry<String, Bitmap>> iter = cache.entrySet().iterator();<span style="white-space:pre"></span>while (iter.hasNext()) {<span style="white-space:pre"></span>Entry<String, Bitmap> entry = iter.next();<span style="white-space:pre"></span>size -= getSizeInBytes(entry.getValue());<span style="white-space:pre"></span>iter.remove();<span style="white-space:pre"></span>if (size <= limit)<span style="white-space:pre"></span>break;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>Log.i(TAG, "Clean cache. New size " + cache.size());<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}<span style="white-space:pre"></span>public void clear() {<span style="white-space:pre"></span>cache.clear();<span style="white-space:pre"></span>}<span style="white-space:pre"></span>/**<span style="white-space:pre"></span> * 图片占用的内存<span style="white-space:pre"></span> * <span style="white-space:pre"></span> * @param bitmap<span style="white-space:pre"></span> * @return<span style="white-space:pre"></span> */<span style="white-space:pre"></span>long getSizeInBytes(Bitmap bitmap) {<span style="white-space:pre"></span>if (bitmap == null)<span style="white-space:pre"></span>return 0;<span style="white-space:pre"></span>return bitmap.getRowBytes() * bitmap.getHeight();<span style="white-space:pre"></span>}}
package com.panpass.main;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.Window;import android.widget.ImageView;import com.example.imgdemo.R;public class MainActivity extends Activity {<span style="white-space:pre"></span>private Context mContext = this;<span style="white-space:pre"></span>private ImageView img1,img2,img3,img4,img5;<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>protected void onCreate(Bundle savedInstanceState) {<span style="white-space:pre"></span>super.onCreate(savedInstanceState);<span style="white-space:pre"></span>getWindow().requestFeature(Window.FEATURE_NO_TITLE);<span style="white-space:pre"></span>setContentView(R.layout.main_acticity);<span style="white-space:pre"></span>img1 = (ImageView) findViewById(R.id.img1);<span style="white-space:pre"></span>img2 = (ImageView) findViewById(R.id.img2);<span style="white-space:pre"></span>img3 = (ImageView) findViewById(R.id.img3);<span style="white-space:pre"></span>img4 = (ImageView) findViewById(R.id.img4);<span style="white-space:pre"></span>img5 = (ImageView) findViewById(R.id.img5);<span style="white-space:pre"></span>ImageManager.getInstance(mContext).loadBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif", new Handler(){<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>public void handleMessage(Message msg) {<span style="white-space:pre"></span>super.handleMessage(msg);<span style="white-space:pre"></span>img1.setImageBitmap((Bitmap)msg.obj);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>});<span style="white-space:pre"></span>ImageManager.getInstance(mContext).loadBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif", new Handler(){<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>public void handleMessage(Message msg) {<span style="white-space:pre"></span>super.handleMessage(msg);<span style="white-space:pre"></span>img2.setImageBitmap((Bitmap)msg.obj);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>});<span style="white-space:pre"></span>ImageManager.getInstance(mContext).loadBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif", new Handler(){<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>public void handleMessage(Message msg) {<span style="white-space:pre"></span>super.handleMessage(msg);<span style="white-space:pre"></span>img3.setImageBitmap((Bitmap)msg.obj);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>});<span style="white-space:pre"></span>ImageManager.getInstance(mContext).loadBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif", new Handler(){<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>public void handleMessage(Message msg) {<span style="white-space:pre"></span>super.handleMessage(msg);<span style="white-space:pre"></span>img4.setImageBitmap((Bitmap)msg.obj);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>});<span style="white-space:pre"></span>ImageManager.getInstance(mContext).loadBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif", new Handler(){<span style="white-space:pre"></span>@Override<span style="white-space:pre"></span>public void handleMessage(Message msg) {<span style="white-space:pre"></span>super.handleMessage(msg);<span style="white-space:pre"></span>img5.setImageBitmap((Bitmap)msg.obj);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>});<span style="white-space:pre"></span>//<span style="white-space:pre"></span>img2.setImageBitmap(ImageManager.getInstance(mContext).getBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif"));<span style="white-space:pre"></span>//<span style="white-space:pre"></span>//<span style="white-space:pre"></span>img3.setImageBitmap(ImageManager.getInstance(mContext).getBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif"));<span style="white-space:pre"></span>//<span style="white-space:pre"></span>img4.setImageBitmap(ImageManager.getInstance(mContext).getBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif"));<span style="white-space:pre"></span>//<span style="white-space:pre"></span>img5.setImageBitmap(ImageManager.getInstance(mContext).getBitmap("https://www.baidu.com/img/baidu_jgylogo3.gif?v=26599715.gif"));<span style="white-space:pre"></span>}}


0 0
原创粉丝点击