Android实现图片异步加载并缓存到本地
在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片。
软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地有没有,如果没有再从网络读取。
下面就分享一下异步加载网络图片的方法吧。
FileCache.java
importjava.io.File;
importandroid.content.Context;
publicclassFileCache{
privateFilecacheDir;
publicFileCache(Contextcontext){
//找一个用来缓存图片的路径
if(android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED))
cacheDir=newFile(android.os.Environment.getExternalStorageDirectory(),
"文件夹名称");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
publicFilegetFile(Stringurl){
Stringfilename=String.valueOf(url.hashCode());
Filef=newFile(cacheDir,filename);
returnf;
}
publicvoidclear(){
File[]files=cacheDir.listFiles();
if(files==null)
return;
for(Filef:files)
f.delete();
}
}
HttpUtil.java
importjava.io.ByteArrayOutputStream;
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.io.UnsupportedEncodingException;
importjava.net.HttpURLConnection;
importjava.net.MalformedURLException;
importjava.net.ProtocolException;
importjava.net.URL;
importjava.net.URLEncoder;
importjava.util.Map;
/**
*Http请求工具类
*
*@authorScorpio.Liu
*
*/
publicclassHttpUtil{
/**
*获取响应字符串
*
*@parampath
*路径
*@paramparameters
*参数
*@return响应字符串
*/
publicstaticStringgetResponseStr(Stringpath,Map<String,String>parameters){
StringBufferbuffer=newStringBuffer();
URLurl;
try{
if(parameters!=null&&!parameters.isEmpty()){
for(Map.Entry<String,String>entry:parameters.entrySet()){
//完成转码操作
buffer.append(entry.getKey()).append("=")
.append(URLEncoder.encode(entry.getValue(),"UTF-8")).append("&");
}
buffer.deleteCharAt(buffer.length()-1);
}
url=newURL(path);
HttpURLConnectionurlConnection=(HttpURLConnection)url.openConnection();
urlConnection.setConnectTimeout(3000);
urlConnection.setRequestMethod("POST");
urlConnection.setDoInput(true);//表示从服务器获取数据
urlConnection.setDoOutput(true);//表示向服务器写数据
//获得上传信息的字节大小以及长度
byte[]mydata=buffer.toString().getBytes();
//表示设置请求体的类型是文本类型
urlConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
urlConnection.setRequestProperty("Content-Length",String.valueOf(mydata.length));
//获得输出流,向服务器输出数据
OutputStreamoutputStream=urlConnection.getOutputStream();
outputStream.write(mydata,0,mydata.length);
outputStream.close();
intresponseCode=urlConnection.getResponseCode();
if(responseCode==200){
returnchangeInputStream(urlConnection.getInputStream());
}
}catch(UnsupportedEncodingExceptione){
e.printStackTrace();
}catch(MalformedURLExceptione){
e.printStackTrace();
}catch(ProtocolExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
returnnull;
}
privatestaticStringchangeInputStream(InputStreaminputStream){
ByteArrayOutputStreamoutputStream=newByteArrayOutputStream();
byte[]data=newbyte[1024];
intlen=0;
Stringresult="";
if(inputStream!=null){
try{
while((len=inputStream.read(data))!=-1){
outputStream.write(data,0,len);
}
result=newString(outputStream.toByteArray(),"UTF-8");
}catch(IOExceptione){
e.printStackTrace();
}
}
returnresult;
}
publicstaticInputStreamgetInputStream(Stringpath){
URLurl;
try{
url=newURL(path);
HttpURLConnectionurlConnection=(HttpURLConnection)url.openConnection();
urlConnection.setConnectTimeout(3000);
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);//表示从服务器获取数据
urlConnection.connect();
if(urlConnection.getResponseCode()==200)
returnurlConnection.getInputStream();
}catch(MalformedURLExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(IOExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}catch(Exceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
returnnull;
}
publicstaticbyte[]readStream(InputStreaminStream)throwsException{
ByteArrayOutputStreamoutSteam=newByteArrayOutputStream();
byte[]buffer=newbyte[1024];
intlen=-1;
while((len=inStream.read(buffer))!=-1){
outSteam.write(buffer,0,len);
}
outSteam.close();
inStream.close();
returnoutSteam.toByteArray();
}
publicstaticvoidCopyStream(Stringurl,Filef){
FileOutputStreamfileOutputStream=null;
InputStreaminputStream=null;
try{
inputStream=getInputStream(url);
byte[]data=newbyte[1024];
intlen=0;
fileOutputStream=newFileOutputStream(f);
while((len=inputStream.read(data))!=-1){
fileOutputStream.write(data,0,len);
}
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}finally{
if(inputStream!=null){
try{
inputStream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
if(fileOutputStream!=null){
try{
fileOutputStream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
}
MemoryCache.java
importjava.lang.ref.SoftReference;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Map;
importandroid.graphics.Bitmap;
publicclassMemoryCache{
privateMap<String,SoftReference<Bitmap>>cache=Collections
.synchronizedMap(newHashMap<String,SoftReference<Bitmap>>());//软引用
publicBitmapget(Stringid){
if(!cache.containsKey(id))
returnnull;
SoftReference<Bitmap>ref=cache.get(id);
returnref.get();
}
publicvoidput(Stringid,Bitmapbitmap){
cache.put(id,newSoftReference<Bitmap>(bitmap));
}
publicvoidclear(){
cache.clear();
}
}
ImageLoader.java
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.UnsupportedEncodingException;
importjava.net.URLEncoder;
importjava.util.Collections;
importjava.util.Map;
importjava.util.WeakHashMap;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importandroid.app.Activity;
importandroid.content.Context;
importandroid.graphics.Bitmap;
importandroid.graphics.BitmapFactory;
importandroid.graphics.drawable.BitmapDrawable;
importandroid.widget.ImageView;
publicclassImageLoader{
privateMemoryCachememoryCache=newMemoryCache();
privateFileCachefileCache;
privateMap<ImageView,String>imageViews=Collections
.synchronizedMap(newWeakHashMap<ImageView,String>());
privateExecutorServiceexecutorService;
privatebooleanisSrc;
/**
*@paramcontext
*上下文对象
*@paramflag
*true为source资源,false为background资源
*/
publicImageLoader(Contextcontext,booleanflag){
fileCache=newFileCache(context);
executorService=Executors.newFixedThreadPool(5);
isSrc=flag;
}
finalintstub_id=R.drawable.ic_launcher;
publicvoidDisplayImage(Stringurl,ImageViewimageView){
Stringu1=url.substring(0,url.lastIndexOf("/")+1);
Stringu2=url.substring(url.lastIndexOf("/")+1);
try{
u2=URLEncoder.encode(u2,"UTF-8");
}catch(UnsupportedEncodingExceptione){
e.printStackTrace();
}
url=u1+u2;
imageViews.put(imageView,url);
Bitmapbitmap=memoryCache.get(url);
if(bitmap!=null){
if(isSrc)
imageView.setImageBitmap(bitmap);
else
imageView.setBackgroundDrawable(newBitmapDrawable(bitmap));
}else{
queuePhoto(url,imageView);
if(isSrc)
imageView.setImageResource(stub_id);
else
imageView.setBackgroundResource(stub_id);
}
}
privatevoidqueuePhoto(Stringurl,ImageViewimageView){
PhotoToLoadp=newPhotoToLoad(url,imageView);
executorService.submit(newPhotosLoader(p));
}
privateBitmapgetBitmap(Stringurl){
try{
Filef=fileCache.getFile(url);
//从sd卡
Bitmapb=onDecodeFile(f);
if(b!=null)
returnb;
//从网络
Bitmapbitmap=null;
System.out.println("ImageLoader-->download");
HttpUtil.CopyStream(url,f);
bitmap=onDecodeFile(f);
returnbitmap;
}catch(Exceptionex){
ex.printStackTrace();
returnnull;
}
}
publicBitmaponDecodeFile(Filef){
try{
returnBitmapFactory.decodeStream(newFileInputStream(f));
}catch(FileNotFoundExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
returnnull;
}
/**
*解码图像用来减少内存消耗
*
*@paramf
*@return
*/
publicBitmapdecodeFile(Filef){
try{
//解码图像大小
BitmapFactory.Optionso=newBitmapFactory.Options();
o.inJustDecodeBounds=true;
BitmapFactory.decodeStream(newFileInputStream(f),null,o);
//找到正确的刻度值,它应该是2的幂。
finalintREQUIRED_SIZE=70;
intwidth_tmp=o.outWidth,height_tmp=o.outHeight;
intscale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE||height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Optionso2=newBitmapFactory.Options();
o2.inSampleSize=scale;
returnBitmapFactory.decodeStream(newFileInputStream(f),null,o2);
}catch(FileNotFoundExceptione){
}
returnnull;
}
/**
*任务队列
*
*@authorScorpio.Liu
*
*/
privateclassPhotoToLoad{
publicStringurl;
publicImageViewimageView;
publicPhotoToLoad(Stringu,ImageViewi){
url=u;
imageView=i;
}
}
classPhotosLoaderimplementsRunnable{
PhotoToLoadphotoToLoad;
PhotosLoader(PhotoToLoadphotoToLoad){
this.photoToLoad=photoToLoad;
}
@Override
publicvoidrun(){
if(imageViewReused(photoToLoad))
return;
Bitmapbmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url,bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayerbd=newBitmapDisplayer(bmp,photoToLoad);
Activitya=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
booleanimageViewReused(PhotoToLoadphotoToLoad){
Stringtag=imageViews.get(photoToLoad.imageView);
if(tag==null||!tag.equals(photoToLoad.url))
returntrue;
returnfalse;
}
/**
*显示位图在UI线程
*
*@authorScorpio.Liu
*
*/
classBitmapDisplayerimplementsRunnable{
Bitmapbitmap;
PhotoToLoadphotoToLoad;
publicBitmapDisplayer(Bitmapb,PhotoToLoadp){
bitmap=b;
photoToLoad=p;
}
publicvoidrun(){
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null){
if(isSrc)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setBackgroundDrawable(newBitmapDrawable(bitmap));
}else{
if(isSrc)
photoToLoad.imageView.setImageResource(stub_id);
else
photoToLoad.imageView.setBackgroundResource(stub_id);
}
}
}
publicvoidclearCache(){
memoryCache.clear();
fileCache.clear();
}
}
使用的时候用ImageLoader这个类就ok了,很方便~
希望本文所述对大家学习Android软件编程有所帮助。