导致图片无法显示的根本原因在于多个同样地址的图片由于采用异步形式,导致耗时长去请求的线程回调时通过imageview 绑定的tag 没等找到 对应的imageview ,所以出现了部分图没加载的现象;
所以为了解决此问题,添加了一个类似缓存的map 存储当时发出请求没能在缓存找到的imageview 按照 地址:images 形式临时存储;等线程取到图片后取出对应的images 一一复制,清空缓存;
下面为解决的代码
1.图片加载工具类:
AsyncImageLoaderForDrawable
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.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.ImageView;
import basic.param.SysParam;
/**
*
* @author wgl
*
*/
public class AsyncImageLoaderForDrawable {
Handler handler;
private TreeMap<String, SoftReference<Drawable>> imageCache;
private Activity ct;
public static final String SD_PATH = SysParam.LOCAL_PATH;
public static final String IMG_CACHE_PATH =SD_PATH+File.separator+"cache"; //网络图片默认缓存路径
public static final String IMG_PATH =SD_PATH+File.separator+"image"; //拍照、相册选择的压缩图片存储路径
public static final String BASE_PATH = SD_PATH; //应用根目录
/**
* 等待被渲染的图片队列,key:加载图片的地址 value:为地址为key的imageview的集合;
*/
private HashMap<String, List<ImageView>> waitCache ;
public AsyncImageLoaderForDrawable(Activity ct) {
// TODO Auto-generated constructor stub
imageCache = new TreeMap<String, SoftReference<Drawable>>();
waitCache = new HashMap<String, List<ImageView>>();
this.ct = ct;
/*
* 初始化cache、image 文件夹
*/
File cacheD = new File(IMG_CACHE_PATH);
if(!cacheD.exists()){
cacheD.mkdirs();
}
cacheD = new File(IMG_PATH);
if(!cacheD.exists()){
cacheD.mkdirs();
}
}
/**
* 异步请求图片并加入缓存, (加载多个相同图片时,耗时长的线程,如果调用者通过tag查找原来的imageview 可能会找不到对应的image,需要单独处理找到image)
* @param imageUrl可以使网络地址或者本地缓存下的文件名
* @param saveName 如果出入的值不为null ,将imageUrl是网络地址的图片保存在 缓存目录下 命名为 saveName
* @param imageCallback
* @return
*/
public Drawable loadDrawable(final String imageUrl,final String saveName,final ImageCallback imageCallback){
if(imageCache.containsKey(imageUrl)){
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if(softReference.get()!=null){//如果没有被回收,使用内存缓存的对象
return softReference.get();
}else{
imageCache.remove(imageUrl);
}
}
final Handler handler2 = new Handler(){
public void handleMessage(final Message message){
ct.runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Map<String, Object> data = (Map<String, Object>) message.obj;
imageCallback.imageLoaded((Drawable)data.get("draw"), (String)data.get("url"));
}
});
}
};
new Thread(){
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl,saveName==null? null:IMG_CACHE_PATH+File.separator+saveName);
Map<String , Object> obj = new HashMap<String, Object>();
obj.put("draw", drawable);
obj.put("url", imageUrl);
Message message = handler2.obtainMessage(0, obj);
handler2.handleMessage(message);//线程通信
}
}.start();
return null;
}
/**
* 异步请求图片并加入缓存, 用于请求处理存在多个地址一样的问题
* @param imageUrl可以使网络地址或者本地缓存下的文件名
* @param saveName 如果出入的值不为null ,将imageUrl是网络地址的图片保存在 缓存目录下 命名为 saveName
* @param imageCallback
* @return
*/
public Drawable loadDrawable(final String imageUrl,final String saveName,ImageView image){
if(imageCache.containsKey(imageUrl)){
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
if(softReference.get()!=null){//如果没有被回收,使用内存缓存的对象
return softReference.get();
}else{
imageCache.remove(imageUrl);
}
}
List<ImageView> images= waitCache.get(imageUrl);
if(images!=null){
images.add(image);
return null;
}else{
images = new ArrayList<ImageView>();
images.add(image);
waitCache.put(imageUrl, images);
}
final Handler handler2 = new Handler(){
public void handleMessage(final Message message){
ct.runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Map<String, Object> data = (Map<String, Object>) message.obj;
List<ImageView> images = waitCache.get((String)data.get("url"));
waitCache.remove(imageUrl);
if(images!=null&&!images.isEmpty()){
for(ImageView img:images){
if(img!=null){
img.setImageDrawable((Drawable)data.get("draw"));
}
}
}
images= null;
data = null;
}
});
}
};
new Thread(){
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl,saveName==null? null:IMG_CACHE_PATH+File.separator+saveName);
Map<String , Object> obj = new HashMap<String, Object>();
obj.put("draw", drawable);
obj.put("url", imageUrl);
Message message = handler2.obtainMessage(0, obj);
handler2.handleMessage(message);//线程通信
}
}.start();
return null;
}
/**
* 从网络地址获取的inputStrean 获取 drawable 对象
* @param url 网络地址 或者本地图片路径 或者指定目录下 IMG_PATH 下的文件名
* @param savename 网络图片要保存到本地的文件名 缓存路径为IMG_CACHE_PATH下
* @return
*/
public Drawable loadImageFromUrl(String url,String savename) {
if(imageCache.containsKey(url)){
SoftReference<Drawable> softReference = imageCache.get(url);
if(softReference.get()!=null){//如果没有被回收,使用内存缓存的对象
return softReference.get();
}
}
imageCache.put(url, null);
InputStream i = null;
Drawable drawable=null ;
if(url.startsWith("http:")){
try {
String name = MD5Util.string2MD5(url);
File img = new File(IMG_CACHE_PATH+File.separator+name);
if(img.exists()){ //查找本地缓存有没有
i = new FileInputStream(img);
drawable = Drawable.createFromStream(i, "src");
}else{
URL m;
m = new URL(url);
URLConnection connection = m.openConnection();
i=connection.getInputStream();
// i = (InputStream) m.getContent();
if(i==null){
return null;
}
if(savename==null){
savename = IMG_CACHE_PATH+File.separator+name;
}
if(savename!=null){
int byteread = 0;
File file =new File(savename);
FileOutputStream fs = new FileOutputStream(file);
byte[] buffer = new byte[1024];
while ( (byteread = i.read(buffer)) != -1) {
fs.write(buffer, 0, byteread);
}
fs.flush();
fs.close();
i.close();
i = new FileInputStream(file);
drawable = Drawable.createFromStream(i, "src");
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
String path= url;
if(url.startsWith(File.separator)||url.startsWith("file:")){//绝对路径
path= url;
if(url.startsWith("file:")){
path =path.substring(path.indexOf("file:")+"file:".length());
}
}else{
path =IMG_PATH+File.separator+url;
}
File img = new File(path);
if(!img.exists()){
return null;
}
try {
i = new FileInputStream(img);
drawable = Drawable.createFromStream(i, "src");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(drawable!=null){
imageCache.put(url, new SoftReference<Drawable>(drawable));//放入缓存drawable的软引用
}
return drawable;
}
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
public HashMap<String, List<ImageView>> getWaitCache() {
return waitCache;
}
}
2.调用形式
public Drawable getImageDrawble(String url,ImageView image){
Drawable drawable = imageLoader.loadDrawable(url, null, image);
if(drawable==null){//解决
return ct.getResources().getDrawable(R.drawable.defalt_image);
}
return drawable;
}
img.setImageDrawable(getImageDrawble(httpHost,img));//异步加载图片
如果存在bug,欢迎指正