Android 实现异步加载图片
麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的.
今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了AsynTask这个API,继续这个类,实现起来非常简单也很方便.在doInBackground()方法里实现下载逻辑.具体实现如下
实现逻辑是:先从内存中读取,如果内存中有这张图片,则直接使用;如果内存没有再到sdcard上读取,如果有则显示;如果sdcard上还没有则到网络上读取.内存中开启缓存是参考了网上的实现.麦洛在这里非常感谢喜欢分享的程序猿们.
publicclassImageDownloaderextendsAsyncTask<String,Integer,Object>{privatestaticfinalStringTAG="ImageDownloader";//为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)privateMap<String,SoftReference<Drawable>>p_w_picpathCache=newHashMap<String,SoftReference<Drawable>>();/***显示图片的控件*/privateImageViewmImageView;publicImageDownloader(ImageViewp_w_picpath){mImageView=p_w_picpath;}@OverrideprotectedvoidonPreExecute(){super.onPreExecute();}@OverrideprotectedObjectdoInBackground(String...params){//Log.i("ImageDownloader","loadingp_w_picpath...");Stringurl=params[0];Drawabledrawable=null;try{if(!"".equals(url)&&url!=null){StringfileName=url.hashCode()+".jpg";//如果缓存过就从缓存中取出数据if(p_w_picpathCache.containsKey(fileName)){SoftReference<Drawable>softReference=p_w_picpathCache.get(fileName);drawable=softReference.get();if(drawable!=null){returndrawable;}}Filedir=newFile(FileConstant.IMAGE_FILE_PATH);if(!dir.exists()){booleanm=dir.mkdirs();}Filefile=newFile(dir,fileName);if(file.exists()&&file.length()>0){Log.i(TAG,"loadp_w_picpathfromsdcard");//如果文件存在则直接读取sdcarddrawable=readFromSdcard(file);}else{//file.createNewFile();Log.i(TAG,"loadp_w_picpathfromnetwork");URLp_w_picpathUrl=newURL(url);//写入sdcardif(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){saveImageFile(p_w_picpathUrl,file);drawable=Drawable.createFromStream(newFileInputStream(file),fileName);}else{//直接从流读取drawable=Drawable.createFromStream(p_w_picpathUrl.openStream(),fileName);}}if(drawable!=null){//保存在缓存中p_w_picpathCache.put(fileName,newSoftReference<Drawable>(drawable));}}}catch(Exceptione){e.printStackTrace();}returndrawable;}/***savep_w_picpath*/privatevoidsaveImageFile(URLurl,Filefile){FileOutputStreamout=null;InputStreamin=null;try{file.deleteOnExit();out=newFileOutputStream(file);in=url.openStream();byte[]buf=newbyte[1024];intlen=-1;while((len=in.read(buf))!=-1){out.write(buf,0,len);out.flush();}}catch(Exceptione){e.printStackTrace();}finally{if(out!=null){try{out.close();}catch(IOExceptione){e.printStackTrace();}}if(in!=null){try{in.close();}catch(IOExceptione){e.printStackTrace();}}}}/***从sdcard中获取图片*/privateDrawablereadFromSdcard(Filefile)throwsException{FileInputStreamin=newFileInputStream(file);returnDrawable.createFromStream(in,file.getName());}@OverrideprotectedvoidonPostExecute(Objectresult){super.onPostExecute(result);Drawabledrawable=(Drawable)result;if(mImageView!=null&&drawable!=null){mImageView.setBackgroundDrawable(drawable);}}@OverrideprotectedvoidonProgressUpdate(Integer...values){super.onProgressUpdate(values);}@OverrideprotectedvoidonCancelled(){super.onCancelled();}}
使用时:
ImageDownloaderloader=newImageDownloader(p_w_picpathView);loader.execute(url);
其实这样的话,还有一些隐患的,就是说这个类实现还是有些问题的.比如每次都在p_w_picpathView中设置网络上的图片时,其实是没有使用到这个类里面的内存缓存的,就是p_w_picpathCache
Map<String,SoftReference<Drawable>>p_w_picpathCache=newHashMap<String,SoftReference<Drawable>>();
因为每次设置p_w_picpathView的时候,都是new了一个ImageDownloader的对象.所以每个ImageDownloader对象里面都是独立的一个p_w_picpathCache.
另外,AsynTask也是一个线程.而每次使用都开一个线程来load 图片,对线程个数没有进行显示,毕竟线程数目还是有限制的.
所以麦洛今天发现了这个问题,于是参考了别人的实现,使用了线程池,实现逻辑也上面的代码一样,先从内存读取,如果没有到sdcard读取,如果还是没有,则是网络读取;实现没有使用AsynTask,具体代码如下:
/***异步加载图片,并将图片设置到ImageView控件中*/publicclassImageDownloaderextendsAsyncTask<String,Integer,Object>{privatestaticfinalStringTAG="ImageDownloader";//为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动)privateMap<String,SoftReference<Drawable>>p_w_picpathCache=newHashMap<String,SoftReference<Drawable>>();/***显示图片的控件*/privateImageViewmImageView;publicImageDownloader(ImageViewp_w_picpath){mImageView=p_w_picpath;}@OverrideprotectedvoidonPreExecute(){super.onPreExecute();}@OverrideprotectedObjectdoInBackground(String...params){//Log.i("ImageDownloader","loadingp_w_picpath...");Stringurl=params[0];Drawabledrawable=null;try{if(!"".equals(url)&&url!=null){StringfileName=url.hashCode()+".jpg";//如果缓存过就从缓存中取出数据if(p_w_picpathCache.containsKey(fileName)){SoftReference<Drawable>softReference=p_w_picpathCache.get(fileName);drawable=softReference.get();if(drawable!=null){returndrawable;}}Filedir=newFile(FileConstant.IMAGE_FILE_PATH);if(!dir.exists()){booleanm=dir.mkdirs();}Filefile=newFile(dir,fileName);if(file.exists()&&file.length()>0){Log.i(TAG,"loadp_w_picpathfromsdcard");//如果文件存在则直接读取sdcarddrawable=readFromSdcard(file);}else{//file.createNewFile();Log.i(TAG,"loadp_w_picpathfromnetwork");URLp_w_picpathUrl=newURL(url);//写入sdcardif(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){saveImageFile(p_w_picpathUrl,file);drawable=Drawable.createFromStream(newFileInputStream(file),fileName);}else{//直接从流读取drawable=Drawable.createFromStream(p_w_picpathUrl.openStream(),fileName);}}if(drawable!=null){//保存在缓存中p_w_picpathCache.put(fileName,newSoftReference<Drawable>(drawable));}}}catch(Exceptione){e.printStackTrace();}returndrawable;}/***savep_w_picpath*/privatevoidsaveImageFile(URLurl,Filefile){FileOutputStreamout=null;InputStreamin=null;try{file.deleteOnExit();out=newFileOutputStream(file);in=url.openStream();byte[]buf=newbyte[1024];intlen=-1;while((len=in.read(buf))!=-1){out.write(buf,0,len);out.flush();}}catch(Exceptione){e.printStackTrace();}finally{if(out!=null){try{out.close();}catch(IOExceptione){e.printStackTrace();}}if(in!=null){try{in.close();}catch(IOExceptione){e.printStackTrace();}}}}/***从sdcard中获取图片*/privateDrawablereadFromSdcard(Filefile)throwsException{FileInputStreamin=newFileInputStream(file);returnDrawable.createFromStream(in,file.getName());}@OverrideprotectedvoidonPostExecute(Objectresult){super.onPostExecute(result);Drawabledrawable=(Drawable)result;if(mImageView!=null&&drawable!=null){mImageView.setBackgroundDrawable(drawable);}}@OverrideprotectedvoidonProgressUpdate(Integer...values){super.onProgressUpdate(values);}@OverrideprotectedvoidonCancelled(){super.onCancelled();}}
这个ImageDownloader2的使用也很简单
publicclassImageUtil{/***p_w_picpathloader*/staticImageDownloader2loader=null;/***loadp_w_picpath*/publicstaticvoidloadImage(Stringurl,finalImageViewp_w_picpathView){if(loader==null){loader=newImageDownloader2();}loader.loadDrawable(url,newImageCallback(){@Overridepublicvoidp_w_picpathLoaded(Drawablep_w_picpathDrawable){if(p_w_picpathDrawable!=null){p_w_picpathView.setBackgroundDrawable(p_w_picpathDrawable);}}});}}
每次在使用是需要调用ImageUtil.loadImage(url,p_w_picpathView)将图片url已经需要显示图片的控件ImageView的引用传入就可以了.
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。