您的位置:首页 > 理论基础 > 计算机网络

【缓存图片】网络图片本地存储策略

2014-03-06 02:49 369 查看
情景一:在开发过程中经常会遇到将网络图片存储到本地,

目的:为了避免图片多次下载

实现策略:使图片的URL与存储文件文件名一一对应。

    如果将文件的URL存储为文件名是行不通的,因为URL会包涵很多特殊字符,文件存储命名是不允许的。

所以我们需要对图片的URL与文件名关联切符合文件名命名规则。

    我的实现方式是采用MD5算法,

   MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。将经过算法处理过的字节数组转换成一个BigInteger类型,再输出为String类型,这样在网络图片URL不变的情况下,图片存储的文件名就唯一。

public static String generateImageId(String imageUrl) {
final String HASH_ALGORITHM = "MD5";
final int RADIX = 10 + 26; // 10 digits + 26 letters

byte[] md5 = null;
try {
MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
digest.update(imageUrl.getBytes());
md5 = digest.digest();
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}

BigInteger bi = new BigInteger(md5).abs();
return bi.toString(RADIX);
}
    

情景二:用户说我们的应用很费流量总是看到在下载东西,且内存被大量的图片占用

目的:减少流量的消耗,减少内存的占用

原因:平凡重复多次下载,安卓手机的RAM存储空间是有限的

实现策略:图片存储在SD开中,首先检测是否有SDcard.下载之前判断本地是否已经存在文件

     首先要判断SDcard是否可以正常使用

/**
* 判断SD卡是否存在
*/
public static boolean checkHasSdcard() {
String status = Environment.getExternalStorageState();
return status.equals(Environment.MEDIA_MOUNTED);
}


     通过上述情景一的方法,我们已经将网络图片URL与本地文件唯一关联起来了,接下来在下载图片时判断本地是否已存在,不存在则下载,减少重复下载次数。

<span style="font-size:18px;">    /**
* 判断SD卡上是否存在此文件
*
* @param fileName
* @return isExists
* @throws IOException
*/
public static boolean hasSDFile(String fileName) throws IOException {
return new File(fileName).exists();
}</span>

情景三:如果我知道了图片的URL,怎么将图片存至本地

目的:通过URL下载至本地

实现策略:利用HttpURLConnection读取流将输入流转换为Bitmap对象再

1.读取输入流

/**
* 使用HttpURLConnection从url获取InputStream
*
* @param httpUrl
* @return inputStream
* @throws IOException
*/
public static InputStream getInputStreamFromUrl(String httpUrl) {
try {
URL url = new URL(httpUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10 * 1000);
if (conn.getResponseCode() == 200) {
return conn.getInputStream();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}


2.通过BitmapFactocy.decodeStream方法将刘转换为Bitmap对象

/**
* 通过url得到Bitmap
*
* @param url
* @return
* @throws Exception
*/
public static Bitmap getBitmapFromUrl(String url) throws Exception {
return BitmapFactory.decodeStream(getInputStreamFromUrl(url));
}


3.将Bitmap对象存储至本地

/**
* 保存图片文件
* @param filePath 本地存储路径
* @param bm
* @param fileName 参考generateId
* @throws IOException
*/
public static void write2SDFromBitmap(String filePath, Bitmap bm, String fileName)
throws IOException {
if (bm == null)
return;

File dirFile = new File(filePath);
if (!dirFile.exists()) {
dirFile.mkdirs();
}

File myCaptureFile = new File(filePath + File.separator + fileName);
if (!myCaptureFile.exists()) {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(myCaptureFile));
bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
}
}
我们在存储时可以对图片进行格式处理。

情景四:我们下载了若干大图,没显示几张就OOM崩溃了

目的:减少图片占用内存

策略:手机上显示的图不需要非常详细,这么理解,有一张10M的图片需要显示而我们真正在手机上看到的或许只有50K,那么加载那些根本就用不到的信息是无用的也是非常消耗资源。而且如果一张图10M普通的加载方式占用的内存是10M+,一个应用分配的栈没几张就被占满,程序的崩溃就不在话下了。

           这里呢网上有非常多的示例讲到关于“网络异步加载双缓存图片的机制”可以搜一搜,三缓存再加上额外存储卡。本篇文章咱不介绍这种机制,看下文。

 

1.通过文件路径获取Bitmap

BitmapFactory.decodeFile(imgPath);
注:这里提示一点,手机图片的尺寸要求是比较特殊的,一般服务器后台返回的图片分辨率也是针对手机特殊规定,一般不超过100K,在开发过程中需要对网络图片的分辨率严格规范。阿里,京东等应用中的图片很大一部分在50k以下。

2.正题,情景四1中你只告诉我怎么将文件路径转化为Bitmap,你还是没有告诉我怎么做处理。不急下面就是你需要的内容。

  2.1 opts.inSampleSize

public static Bitmap readBitMap(Context context, int resId) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
opt.inSampleSize = 4;//缩小为原始的1/16
// 获取资源图片
InputStream is = context.getResources().openRawResource(resId);
return BitmapFactory.decodeStream(is, null, opt);


  2.2 opt.inJustDecodeBounds

public static Bitmap readBitMap(Context context, int resId) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
opt.inJustDecodeBounds = true;//设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出/                //原始图片的长度和宽度
// 获取资源图片
InputStream is = context.getResources().openRawResource(resId);
BitmapFactory.decodeStream(is, null, opt);
int width_tmp = opt.outWidth, height_tmp = opt.outHeight;
opt.outWidth = width_tmp/2;
opt.outHeight = height_tmp/2;
opt.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is, null, opt);
}


这就是一个非常简单的网络图片的存储策略,从图片下载到图片显示,是不是又领悟了些什么呢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐