图片的三级缓冲问题
- 简述
最近在做一个新闻客户端的项目,项目中涉及到许多图片的加载,这些图片在每次启动时都需要从网络中获取。但是,在没有连接wifi的情况下,为了减少流量的消耗,系统内部就需要有缓冲的策略,尽可能的减少流量的消耗。 缓冲策略
当根据url来获取数据时,我们的大概步骤如下:
-从内存中查找
-从缓冲中查找
-从网络中查找代码实现
/**ImageCache.java**/
package cn.it.huanchong;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.util.Log;
public class ImageCache {
//一级缓冲
private LruCache<String, Bitmap> cache = null;
//使用线程池
private ExecutorService threadPool = null;
private File localDir = null;
public ImageCache(Context context){
threadPool = Executors.newFixedThreadPool(5);//创建5个线程
localDir = context.getCacheDir();//缓冲目录
//设置内存的大小
long maxSize = Runtime.getRuntime().maxMemory()/8;
cache = new LruCache<String, Bitmap>((int) maxSize){
//图片大小的计算规则
@Override
protected int sizeOf(String key, Bitmap value) {
int byteRow = value.getRowBytes();
int rowCount = value.getHeight();
return byteRow*rowCount;
}
};
}
public Bitmap getBitmap(String url,Handler handler){
//从内存获取图片
Bitmap bitmap = getFromCache(url);
if(bitmap != null){
Log.i("xinwen", "从内存取得图片");
return bitmap;
}
//从缓冲获取图片
bitmap = getFromLocal(url);
if(bitmap != null){
Log.i("xinwen", "从本地取得图片");
return bitmap;
}
//从网络中获取图片
getFromNet(url,handler);
return null;
}
private class ImageRunable implements Runnable{
private String url;
private Handler handler;
public ImageRunable(String url,Handler handler) {
this.url= url;
this.handler = handler;
}
@Override
public void run() {
try {
URL urlObj = new URL(url);
//访问网络
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
conn.setRequestMethod("GET");//请求方法
conn.setConnectTimeout(5000);//请求时间
if(200==conn.getResponseCode()){
InputStream input = conn.getInputStream();
//使用工具快速生成bitmap对象
Bitmap bitmap = BitmapFactory.decodeStream(input);
Message msg = new Message();
msg.what=200;
HashMap<String, Object> data = new HashMap<String, Object>();
data.put("url", url);
data.put("bitmap", bitmap);
msg.obj = data;
handler.sendMessage(msg);
//保存到集合
cache.put(url, bitmap);
//保存到文件目录
writeToLocal(url,bitmap);
return;
}
} catch (Exception e) {
e.printStackTrace();
}
Message msg = new Message();
msg.what=404;
handler.sendMessage(msg);
}
}
//将图片保存成文件
private void writeToLocal(String url, Bitmap bitmap) {
try {
String rightName = URLEncoder.encode(url, "UTF-8");
File imageFile = new File(localDir.getAbsoluteFile()+"/"+rightName);
if(!imageFile.exists()){
imageFile.createNewFile();
}
//打开文件输出流
FileOutputStream fos = new FileOutputStream(imageFile);
bitmap.compress(CompressFormat.JPEG, 80, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//从网络中获取图片
private void getFromNet(String url, Handler handler) {
ImageRunable r = new ImageRunable(url,handler);
//获取一个线程
threadPool.execute(r);
}
//从缓冲获取图片
private Bitmap getFromLocal(String url) {
try {
//Android是基于linux的,http://www.qq.com,系统无法将含有 : / 的特殊符号存储成文件名
//通过以下方式可以将特殊符号转化成%ss%dd进行存储
String rightName = URLEncoder.encode(url, "UTF-8");
File imageFile = new File(localDir.getAbsoluteFile()+"/"+rightName);
//使用图片工具类BitmapFactory 将文件转换成图片
Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
//为了下次访问提高速度,添加到集合中
cache.put(url, bitmap);
return bitmap;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
//从内存获取图片
private Bitmap getFromCache(String url) {
// TODO Auto-generated method stub
return cache.get(url);
}
}
/**MainActivity.java**/
package cn.it.huanchong;
import java.util.HashMap;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
public class MainActivity extends Activity {
//图片的地址
String url1 = "http://172.16.114.211:8080/web/guide_1.png";
String url2 = "http://172.16.114.211:8080/web/guide_2.png";
String url3 = "http://172.16.114.211:8080/web/guide_3.png";
private ImageView img1;
private ImageView img2;
private ImageView img3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img1 = (ImageView) findViewById(R.id.img1);
img2 = (ImageView) findViewById(R.id.img2);
img3 = (ImageView) findViewById(R.id.img3);
//获取图片并将图片添加到ImageView中
ImageCache cache = new ImageCache(getBaseContext());
Bitmap bitmap1 = cache.getBitmap(url1, handler);
img1.setImageBitmap(bitmap1);
Bitmap bitmap2 = cache.getBitmap(url2, handler);
img2.setImageBitmap(bitmap2);
Bitmap bitmap3 = cache.getBitmap(url3, handler);
img3.setImageBitmap(bitmap3);
}
//获取通过handler发送过来的网络图片
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 200:
HashMap<String, Object> map = (HashMap<String, Object>) msg.obj;
String url = (String) map.get("url");
Bitmap bitmap = (Bitmap) map.get("bitmap");
//获取图片并将图片添加到ImageView中
if(url1.equals(url)){
img1.setImageBitmap(bitmap);
}else if(url2.equals(url)){
img2.setImageBitmap(bitmap);
}else if(img3.equals(url)){
img3.setImageBitmap(bitmap);
}
break;
default:
break;
}
};
};
}