对网络图片下载,并显示在相对应的控件上,为了避免重复连网下载,可以对相应的图片进行双缓存设计,节省时间和流量
设计罗辑
当app启动后,如果控件需要显示网络图片,首先从自己的内存缓存读取,如果没有,再从自己的磁盘缓存读取,再没有,直接上网下载(下载时按照要显示的比例下载保存图片,不用下原图),下载好图片后,保存到内存缓存和磁盘缓存中,当下次需再重新加载图片时,又重新按照加载顺序一一读取,如果读取到直接显示图片即可
内存缓存在app关闭时会自动释放,磁盘缓存则在app册除时会自动删除,而且当app的版本更新时,碰盘缓存会自动删掉原来的图片,而更新最新版的图片
主Activity
package com.example.xin_utils_downwebimage2cachedemo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HttpsURLConnection;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import com.jakewharton.disklrucache.DiskLruCache;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.support.v4.util.LruCache;
import android.view.Display;
import android.view.Menu;
import android.view.View;
import android.widget.ImageView;
/**
* 手动双缓存图片,1存放内存缓存,2存放磁盘缓存 在加载图片时,先从内存缓存取,如果没有,再从磁盘缓存取,再没有,从网络下载
* 下载后马上存进内存缓存和磁盘缓存 以上功能,在ImageLoder第三方框架可以轻松实现,在这里只是为了熟悉相同的原理而自己制作
*
* @author Administrator
*
*/
public class MainActivity extends Activity {
private static final String IMAGEPATH = "http://pic2.52pk.com/files/120203/309295_150703_3923.jpg";
private static final String KEY = "B1";
ImageView iv;
Bitmap bitmap;
LruCache lru;
DiskLruCache diskLryCache;
MyHandler myHandler;
String md5Key;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myHandler = new MyHandler();
iv = (ImageView) findViewById(R.id.imageView1);
init();
}
private void init() {
// 获取到当前activity可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
// LruCache通过构造函数传入缓存值,以KB为单位。
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 使用最大可用内存值的1/8作为缓存的大小。
int cacheSize = maxMemory / 8;
System.out.println("cacheSize=" + cacheSize);
lru = new LruCache<String, Bitmap>(cacheSize);
File cacheDir = getDiskCacheDir(this, "bitmap");
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
try {
diskLryCache = DiskLruCache.open(cacheDir, getAppVersion(this), 1,
10 * 1024 * 1024);
} catch (IOException e) {
e.printStackTrace();
}
md5Key = encrypByMd5(IMAGEPATH);
}
// 获取SD卡的磁盘缓存地址
public File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
// 当SD卡存在或者SD卡不可被移除的时候
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
System.out.println("碰盘缓存地址=" + cachePath + File.separator + uniqueName);
return new File(cachePath + File.separator + uniqueName);
}
// 获取当前app的版本号
public int getAppVersion(Context context) {
try {
PackageInfo info = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
return info.versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 1;
}
public void addLocalImage(View view) {
System.out.println("加载本地图片lc");
myHandler.obtainMessage(0).sendToTarget();
}
public void clickDown(View view) {
System.out.println("onclick");
downWebImage(IMAGEPATH);
}
// 使用异步加载网络图片,也可以用new Thread().start()
private void downWebImage(final String url) {
// 参数:1= 传进来的参数url类形,2=下载网络图片时的%比,3=下载的文件类形
new AsyncTask<String, Integer, Bitmap>() {
@Override
protected Bitmap doInBackground(String... params) {
try {
if (lru.get(KEY) == null) {
System.out.println("虚拟内存无文件");
DiskLruCache.Snapshot snapShot = diskLryCache
.get(md5Key);
if (snapShot != null) {
System.out.println("磁盘内存有文件");
InputStream is = snapShot.getInputStream(0);
bitmap = BitmapFactory.decodeStream(is);
} else {
System.out.println("磁盘内存无文件");
URL urlS = new URL(params[0]);
HttpURLConnection conn = (HttpURLConnection) urlS
.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
byte[] bytes = toByteArray(is);
Options opts = new Options();
// 根据计算出的比例进行缩放(根据不同的手机屏幕大小,获取最适合的图片大小,
// 可以节省内存空间,不用每次都把原图下载),也可以指定下载大小
int scale = getScare(params[0],bytes,opts);
opts.inSampleSize = scale;
opts.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
System.out.println("lru=空,创建");
try {
DiskLruCache.Editor editor = diskLryCache
.edit(md5Key);
if (editor != null) {
OutputStream outputStream = editor
.newOutputStream(0);
if (bitmap.compress(
Bitmap.CompressFormat.JPEG, 100,
outputStream)) {
editor.commit();
} else {
editor.abort();
}
}
diskLryCache.flush();
} catch (IOException e) {
e.printStackTrace();
}
// is.close();
// conn.disconnect();
}
// if (!filePath.exists()) {
// System.out.println("SD卡无文件");
// URL urlS = new URL(params[0]);
// HttpURLConnection conn = (HttpURLConnection)
// urlS.openConnection();
// conn.connect();
// InputStream is = conn.getInputStream();
// Options opts = new Options();
// // 根据计算出的比例进行缩放(根据不同的手机屏幕大小,获取最适合的图片大小,
// //可以节省内存空间,不用每次都把原图下载),也可以指定下载大小
// int scale = getScare(params[0]);
// opts.inSampleSize = scale;
// System.out.println("lru=空,创建");
// bitmap = BitmapFactory.decodeStream(is, null, opts);
// saveBitmapToFile(bitmap, SDPATH);
// System.out.println("宽="+bitmap.getWidth());
// System.out.println("高="+bitmap.getHeight());
// is.close();
// conn.disconnect();
// }else{
// System.out.println("文件存在于SD卡上");
// bitmap = downFile();
// }
lru.put(KEY, bitmap);
} else {
System.out.println("内存有文件");
bitmap = (Bitmap) lru.get(KEY);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
protected void onPostExecute(Bitmap bitmap1) {
System.out.println("onPostExecute");
iv.setImageBitmap(bitmap1);
};
}.execute(url);
}
private byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
return output.toByteArray();
}
// private boolean downloadUrlToStream(String urlString,
// OutputStream outputStream) {
// HttpURLConnection urlConnection = null;
// BufferedOutputStream out = null;
// BufferedInputStream in = null;
// try {
// final URL url = new URL(urlString);
// urlConnection = (HttpURLConnection) url.openConnection();
// in = new BufferedInputStream(urlConnection.getInputStream(),
// 8 * 1024);
// out = new BufferedOutputStream(outputStream, 8 * 1024);
// int b;
// while ((b = in.read()) != -1) {
// out.write(b);
// }
// return true;
// } catch (final IOException e) {
// e.printStackTrace();
// } finally {
// if (urlConnection != null) {
// urlConnection.disconnect();
// }
// try {
// if (out != null) {
// out.close();
// }
// if (in != null) {
// in.close();
// }
// } catch (final IOException e) {
// e.printStackTrace();
// }
// }
// return false;
// }
// public static void saveBitmapToFile(Bitmap bitmap, String _file)
// throws IOException {
// BufferedOutputStream os = null;
// try {
// File file = new File(_file);
// // String _filePath_file.replace(File.separatorChar +
// // file.getName(), "");
// int end = _file.lastIndexOf(File.separator);
// String _filePath = _file.substring(0, end);
// File filePath = new File(_filePath);
// if (!filePath.exists()) {
// filePath.mkdirs();
// }
// file.createNewFile();
// os = new BufferedOutputStream(new FileOutputStream(file));
// bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
// } finally {
// if (os != null) {
// try {
// os.close();
// } catch (IOException e) {
// }
// }
// }
// }
// 获取当前要使用图片的比例值
public int getScare(String url,byte[] bytes,Options opts1) {
System.out.println("url="+url);
try {
// 不下载图片,只为了获取实际宽高
opts1.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts1);
int imageWidth = opts1.outWidth;
int imageHeight = opts1.outHeight;
System.out.println("imageWidth=" + opts1.outWidth);
Display display = MainActivity.this.getWindowManager()
.getDefaultDisplay();
int screenWidth = display.getWidth();
int screenHeight = display.getHeight();
// 根据屏幕大小计算比例参数
// int widthscale = imageWidth / screenWidth;
// int heightscale = imageHeight / screenHeight;
// 根据指定图片大小计算比例参数
int widthscale = imageWidth / 200;
int heightscale = imageHeight / 100;
int scale = widthscale > heightscale ? widthscale : heightscale;
System.out.println("scale="+scale);
return scale;
} catch (Exception e) {
e.printStackTrace();
}
return 1;// 网络连接失败时默认返回1
}
// 传进字符串,转成md5码
private String encrypByMd5(String context) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(context.getBytes());// update处理
byte[] encryContext = md.digest();// 调用该方法完成计算
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < encryContext.length; offset++) {// 做相应的转化(十六进制)
i = encryContext[offset];
if (i < 0)
i += 256;
if (i < 16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
return buf.toString();
// System.out.println("32result: " + buf.toString());// 32位的加密
// System.out.println("16result: " + buf.toString().substring(8,
// 24));// 16位的加密
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
// 测试用
iv.setImageResource(R.drawable.ic_launcher);
break;
default:
break;
}
}
}
}