在开发中,遇到很多大量图片呈现给用户,那么我们怎么又快又高效的显示给用户呢?
在这里结合前人写的文章和自己的一些改动。
一般我们写的过程中是这么处理的:先去缓存(WeakHashMap<String, Bitmap>来存储图片)中提取,这样速度快又节约流量,缓存中没有再选择本地有图片没有,如果两者都没有则只有从网络去获取。
我们先分开讲解
方法一:网络下载
方法二:从本地文件加载
方法三:从缓存中读取
先来说方法一:
加载很多图片的时候,我们经常用多线程在后台下载,在handler中将图片呈现在界面。
直接上代码
//网络获取图片
protected Bitmap getNetBitmapByURL(String urlString) {
URL url = null;
InputStream inputStream = null;
HttpURLConnection urlConnection = null;
Bitmap bmp = null;
try {
url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(10000);
inputStream = urlConnection.getInputStream();
byte[] bt = getBytesFromStream(inputStream);
bmp = BitmapFactory.decodeByteArray(bt, 0, bt.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
try {
inputStream.close();
inputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != urlConnection) {
urlConnection.disconnect();
urlConnection = null;
}
}
return bmp;
}
// 数据流
private byte[] getBytesFromStream(InputStream inputStream) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while (len != -1) {
try {
len = inputStream.read(b);
} catch (IOException e) {
e.printStackTrace();
}
if (len != -1) {
baos.write(b, 0, len);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return baos.toByteArray();
}
这个地方获取了Bitmap 用handler呈现就很好搞定
再来说方法二本地获取:
直接根据图片路径获取Bitmap
private boolean cacheBmpToMemory(File file) {
boolean sucessed = true;
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
sucessed = false;
}
byte[] bs = getBytesFromStream(inputStream);
Bitmap bitmap = BitmapFactory.decodeByteArray(bs, 0, bs.length);
if (bitmap == null) {
return null;
}
return bitmap;
}
private byte[] getBytesFromStream(InputStream inputStream) {
boolean b2 = true;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while (len != -1 && b2) {
try {
len = inputStream.read(b);
if (len != -1) {
baos.write(b, 0, len);
}
} catch (IOException e) {
b2 = false;
try {
inputStream.close();
} catch (IOException e1) {
}
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return baos.toByteArray();
}
方法三缓存获取:
用弱引用:WeakHashMap<String, Bitmap>,以弱键 实现的基于哈希表的 Map,在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除。
WeakHashMap 中的每个键对象间接地存储为一个弱引用的指示对象。因此,不管是在映射内还是在映射之外,只有在垃圾回收器清除某个键的弱引用之后,该键才会自动移除
这个地方结合方法一和方法二,写了一个有关图片缓存的解决方法。
java文件:
ImageCache.java
package com.imageService;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.WeakHashMap;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.os.Environment;
public class ImageCache extends WeakHashMap<String, Bitmap> {
private static ImageCache mNetImageViewCache = new ImageCache();
private static final String CACHE_FILE = "/Cache";
private ImageCache() {
}
public static ImageCache getInstance() {
return mNetImageViewCache;
}
/**
* 判断图片是否存在首先判断内存中是否存在然后判断本地是否存在
*
* @param url
* @return
*/
public boolean isBitmapExit(String url) {
boolean isExit = containsKey(url);
if (false == isExit) {
isExit = isLocalHasBmp(url);
}
return isExit;
}
/*
* 判断本地有没有
*/
private boolean isLocalHasBmp(String url) {
boolean isExit = true;
String name = changeUrlToName(url);
String filePath = isCacheFileIsExit();
File file = new File(filePath, name);
if (file.exists()) {
isExit = cacheBmpToMemory(file, url);
} else {
isExit = false;
}
return isExit;
}
/*
* 将本地图片缓存到内存中
*/
private boolean cacheBmpToMemory(File file, String url) {
boolean sucessed = true;
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
sucessed = false;
}
byte[] bs = getBytesFromStream(inputStream);
Bitmap bitmap = BitmapFactory.decodeByteArray(bs, 0, bs.length);
if (bitmap == null) {
return false;
}
this.put(url, bitmap, false);
return sucessed;
}
private byte[] getBytesFromStream(InputStream inputStream) {
boolean b2 = true;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while (len != -1 && b2) {
try {
len = inputStream.read(b);
if (len != -1) {
baos.write(b, 0, len);
}
} catch (IOException e) {
b2 = false;
try {
inputStream.close();
} catch (IOException e1) {
}
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return baos.toByteArray();
}
/*
* 判断缓存文件夹是否存在如果存在怎返回文件夹路径,如果不存在新建文件夹并返回文件夹路径
*/
private String isCacheFileIsExit() {
String filePath = "";
String rootpath = "";
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
rootpath = Environment.getExternalStorageDirectory().toString();
}
filePath = rootpath + CACHE_FILE;
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}
return filePath;
}
/*
* 将url变成图片的地址
*/
private String changeUrlToName(String url) {
String name = url.replaceAll(":", "_");
name = name.replaceAll("//", "_");
name = name.replaceAll("/", "_");
name = name.replaceAll("=", "_");
name = name.replaceAll(",", "_");
name = name.replaceAll("&", "_");
return name;
}
public Bitmap put(String key, Bitmap value) {
String filePath = isCacheFileIsExit();
String name = changeUrlToName(key);
File file = new File(filePath, name);
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
value.compress(CompressFormat.JPEG, 100, outputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
if (null != outputStream)
outputStream.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
if (null != outputStream)
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
if (null != outputStream) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
outputStream = null;
}
return super.put(key, value);
}
/**
*
* @param key
* @param value
* @param isCacheToLocal
* 是否缓存到本地
* @return
*/
public Bitmap put(String key, Bitmap value, boolean isCacheToLocal) {
if (isCacheToLocal) {
return this.put(key, value);
} else {
return super.put(key, value);
}
}
}
ImageService.java
package com.imageService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ImageView;
/**
* @author jingche.yhq
使用说明:
1.先增加权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2.图片URL和ImageView直接输入函数
EX:
ImageService imageService = new ImageService(this);
ImageView imageView;
imageService.setBitmapByURL2("http://i1.itc.cn/20120801/a75_b0e447db_3573_ab5c_2058_5845d13545b9_1.jpg", imageView,defaultBitmap);
*/
public class ImageService {
//*********************************************线程池获取图片资源******************************************************
//本地数据缓存
public Map<String, SoftReference<Bitmap>> imageCacheMap = new HashMap<String, SoftReference<Bitmap>>();
//固定五个线程来执行任务
private ExecutorService executorService = Executors.newFixedThreadPool(5);
//回调函数使用
final static ImageService imageService = new ImageService();
public static ImageService getInstance(){
return imageService;
}
/**
* 将图片放进缓存,图片名称是由URL去掉一些符号得到
*
* @param url
* 地址
* @param bitmap
* 图片
*/
public void putImageCache(String url, Bitmap bitmap) {
try {
if(!ImageCache.getInstance().isBitmapExit(url));
ImageCache.getInstance().put(url, bitmap, true);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param url图片URL
*
* @param imageView imageView
*
* @param defaultBitmap 获取图片失败这显示默认图片
*/
public void setBitmapByURL(String url,final ImageView imageView,final Bitmap defaultBitmap,boolean isCacheToLocal) {
//采用Handler+Thread+封装外部接口
//如果缓存过就会从缓存中取出图像,ImageCallback接口中方法也不会被执行
Bitmap cacheImage = loadBitmap(url,imageView,isCacheToLocal,new ImageCallback() {
//请参见实现:如果第一次加载URL时下面方法会执行
@Override
public void imageLoad(ImageView imageView, Bitmap bitmap) {
//如果返回的Bitmap为空这选择默认图片
if (bitmap!=null) {
imageView.setImageBitmap(bitmap);
}else {
imageView.setImageBitmap(defaultBitmap);
}
}
});
if(cacheImage!=null){
imageView.setImageBitmap(cacheImage);
}else {
// imageView.setImageBitmap(defaultBitmap);
}
}
/**
*
* @param imageUrl 图像URL地址
* @param imageCallback 回调接口
* @return 返回内存中缓存的图像,第一次加载返回null
*/
public Bitmap loadBitmap(final String imageUrl,final ImageView imageView,final boolean isCacheToLocal,final ImageCallback imageCallback) {
//如果缓存过就从缓存中取出数据
final Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
imageCallback.imageLoad(imageView, (Bitmap)msg.obj);
}
};
if (imageCacheMap.containsKey(imageUrl)) {
Log.e("提示", "缓存获取图片");
SoftReference<Bitmap> softReference = imageCacheMap.get(imageUrl);
if (softReference.get() != null) {
return softReference.get();
}
}else
if(ImageCache.getInstance().isBitmapExit(imageUrl)){
Log.e("提示", "本地获取图片");
Bitmap bitmap=null;
try {
bitmap = ImageCache.getInstance().get(imageUrl);
} catch (Exception e) {
bitmap = null;
}
return bitmap;
}
else {
//缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中
executorService.submit(new Runnable() {
public void run() {
try {
//获取图片
final Bitmap bitmap = getNetBitmapByURL(imageUrl);
//将图片放置到内存中
Log.e("提示", "网络获取图片"+Thread.currentThread().getName());
if(bitmap!=null){
Log.e("提示", "存储图");
imageCacheMap.put(imageUrl, new SoftReference<Bitmap>(bitmap));
ImageCache.getInstance().put(imageUrl, bitmap, isCacheToLocal);
}
Message msg = handler.obtainMessage(0, bitmap);
handler.sendMessage(msg);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
return null;
}
//网络获取图片
protected Bitmap getNetBitmapByURL(String urlString) {
URL url = null;
InputStream inputStream = null;
HttpURLConnection urlConnection = null;
Bitmap bmp = null;
try {
url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setConnectTimeout(10000);
inputStream = urlConnection.getInputStream();
byte[] bt = getBytesFromStream(inputStream);
bmp = BitmapFactory.decodeByteArray(bt, 0, bt.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != inputStream) {
try {
inputStream.close();
inputStream = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != urlConnection) {
urlConnection.disconnect();
urlConnection = null;
}
}
return bmp;
}
// 数据流
private byte[] getBytesFromStream(InputStream inputStream) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while (len != -1) {
try {
len = inputStream.read(b);
} catch (IOException e) {
e.printStackTrace();
}
if (len != -1) {
baos.write(b, 0, len);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return baos.toByteArray();
}
//对外界开放的回调接口
private interface ImageCallback {
//注意 此方法是用来设置目标对象的图像资源
public void imageLoad(ImageView imageView, Bitmap bitmap);
}
}
test
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageService imageService = new ImageService();
ImageView imageView = (ImageView)findViewById(R.id.imageView1);
imageService.setBitmapByURL("http://i1.itc.cn/20120801/a75_b0e447db_3573_ab5c_2058_5845d13545b9_1.jpg", imageView,BitmapFactory.decodeResource(getResources(), R.drawable.icon));
}
呵呵!很多不足,欢迎拍砖哈。