实现二级缓存加载图片的功能,在使用diskLruCache时,需先在工程中添加名为libcore.io的包,并将diskLruCache.Java文件放进去。diskLruCache直接百度下载即可。
在GrIDVIEw的适配器中,为ImageVIEw添加图片时,先从内存缓存中加载,内存中无缓存的话则在磁盘缓存中加载,磁盘缓存也没有的话开启线程下载,然后将下载的图片缓存到磁盘,内存中。下载的图片最好先进行压缩,文章最后给出了压缩代码,但本例中并未实现压缩。
/*二级缓存实现图片墙功能,先在内存中加载缓存,内存中无缓存的话到磁盘缓存中加载,仍然没有的话开启线程下载图片,下载后缓存到磁盘中,然后缓存到内存中*/
public class ErJiHuanCun extends ArrayAdapter<String> { /** * 记录所有正在下载或等待下载的任务。 */ private Set<BitmapWorkerTask> taskCollection; /** * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。 */ private LruCache<String,Bitmap> mMemoryCache; /** * 图片硬盘缓存核心类。 */ private diskLruCache mdiskLruCache; /** * GrIDVIEw的实例 */ private GrIDVIEw mPhotoWall; /** * 记录每个子项的高度。 */ private int mItemHeight = 0; public ErJiHuanCun(Context context,int textVIEwResourceID,String[] objects,GrIDVIEw photoWall) { super(context,textVIEwResourceID,objects); mPhotoWall = photoWall; taskCollection = new HashSet<BitmapWorkerTask>(); // 获取应用程序最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; // 设置图片缓存大小为程序最大可用内存的1/8 mMemoryCache = new LruCache<String,Bitmap>(cacheSize) { @OverrIDe protected int sizeOf(String key,Bitmap bitmap) { return bitmap.getByteCount(); } }; try { // 获取图片缓存路径 file cacheDir = getdiskCacheDir(context,"thumb"); if (!cacheDir.exists()) { cacheDir.mkdirs(); } // 创建diskLruCache实例,初始化缓存数据 mdiskLruCache = diskLruCache .open(cacheDir,getAppVersion(context),1,10 * 1024 * 1024); } catch (IOException e) { e.printstacktrace(); } } @OverrIDe public VIEw getVIEw(int position,VIEw convertVIEw,VIEwGroup parent) { final String url = getItem(position); VIEw vIEw; if (convertVIEw == null) { vIEw = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout,null); } else { vIEw = convertVIEw; } final ImageVIEw imageVIEw = (ImageVIEw) vIEw.findVIEwByID(R.ID.photo); if (imageVIEw.getLayoutParams().height != mItemHeight) { imageVIEw.getLayoutParams().height = mItemHeight; } // 给ImageVIEw设置一个Tag,保证异步加载图片时不会乱序 imageVIEw.setTag(url); imageVIEw.setimageResource(R.drawable.ic_launcher); loadBitmaps(imageVIEw,url); return vIEw; } /** * 将一张图片存储到LruCache中。 * * @param key * LruCache的键,这里传入图片的URL地址。 * @param bitmap * LruCache的键,这里传入从网络上下载的Bitmap对象。 */ public voID addBitmapToMemoryCache(String key,Bitmap bitmap) { if (getBitmapFromMemoryCache(key) == null) { mMemoryCache.put(key,bitmap); } } /** * 从LruCache中获取一张图片,如果不存在就返回null。 * * @param key * LruCache的键,这里传入图片的URL地址。 * @return 对应传入键的Bitmap对象,或者null。 */ public Bitmap getBitmapFromMemoryCache(String key) { return mMemoryCache.get(key); } /** * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageVIEw的Bitmap对象, * 如果发现任何一个ImageVIEw的Bitmap对象不在缓存中,就会开启异步线程去下载图片。 */ public voID loadBitmaps(ImageVIEw imageVIEw,String imageUrl) { try { Bitmap bitmap = getBitmapFromMemoryCache(imageUrl); if (bitmap == null) { BitmapWorkerTask task = new BitmapWorkerTask(); taskCollection.add(task); task.execute(imageUrl); } else { if (imageVIEw != null && bitmap != null) { imageVIEw.setimageBitmap(bitmap); } } } catch (Exception e) { e.printstacktrace(); } } /** * 取消所有正在下载或等待下载的任务。 */ public voID cancelAllTasks() { if (taskCollection != null) { for (BitmapWorkerTask task : taskCollection) { task.cancel(false); } } } /** * 根据传入的uniquename获取硬盘缓存的路径地址。 */ public file getdiskCacheDir(Context context,String uniquename) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new file(cachePath + file.separator + uniquename); } /** * 获取当前应用程序的版本号。 */ public int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackagename(),0); return info.versionCode; } catch (nameNotFoundException e) { e.printstacktrace(); } return 1; } /** * 设置item子项的高度。 */ public voID setItemHeight(int height) { if (height == mItemHeight) { return; } mItemHeight = height; notifyDataSetChanged(); } /** * 使用MD5算法对传入的key进行加密并返回。 */ public String hashKeyFordisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } /** * 将缓存记录同步到journal文件中。 */ public voID flushCache() { if (mdiskLruCache != null) { try { mdiskLruCache.flush(); } catch (IOException e) { e.printstacktrace(); } } } private String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } /** * 异步下载图片的任务。 * * */ class BitmapWorkerTask extends AsyncTask<String,VoID,Bitmap> { /** * 图片的URL地址 */ private String imageUrl; @OverrIDe protected Bitmap doInBackground(String... params) { imageUrl = params[0]; fileDescriptor fileDescriptor = null; fileinputStream fileinputStream = null; Snapshot snapShot = null; try { // 生成图片URL对应的key final String key = hashKeyFordisk(imageUrl); // 查找key对应的缓存 snapShot = mdiskLruCache.get(key); if (snapShot == null) { // 如果没有找到对应的缓存,则准备从网络上请求数据,并写入缓存 diskLruCache.Editor editor = mdiskLruCache.edit(key); if (editor != null) { OutputStream outputStream = editor.newOutputStream(0); if (downloadUrlToStream(imageUrl,outputStream)) { editor.commit(); } else { editor.abort(); } } // 缓存被写入后,再次查找key对应的缓存 snapShot = mdiskLruCache.get(key); } if (snapShot != null) { fileinputStream = (fileinputStream) snapShot.getinputStream(0); fileDescriptor = fileinputStream.getFD(); } // 将缓存数据解析成Bitmap对象 Bitmap bitmap = null; if (fileDescriptor != null) { // bitmap = BitmapFactory.decodefileDescriptor(fileDescriptor); WindowManager wm= (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE); int wIDth=wm.getDefaultdisplay().getWIDth(); bitmap= ImageResizer.decodeSampleBithmapFromfileDescriptor(fileDescriptor,wIDth/3,wIDth/3); } if (bitmap != null) { // 将Bitmap对象添加到内存缓存当中 addBitmapToMemoryCache(params[0],bitmap); } return bitmap; } catch (IOException e) { e.printstacktrace(); } finally { if (fileDescriptor == null && fileinputStream != null) { try { fileinputStream.close(); } catch (IOException e) { } } } return null; } @OverrIDe protected voID onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); // 根据Tag找到相应的ImageVIEw控件,将下载好的图片显示出来。 ImageVIEw imageVIEw = (ImageVIEw) mPhotoWall.findVIEwWithTag(imageUrl); if (imageVIEw != null && bitmap != null) { imageVIEw.setimageBitmap(bitmap); } taskCollection.remove(this); } /** * 建立http请求,并获取Bitmap对象。 * * @param imageUrl * 图片的URL地址 * @return 解析后的Bitmap对象 */ private boolean downloadUrlToStream(String urlString,OutputStream outputStream) { httpURLConnection urlConnection = null; bufferedoutputstream out = null; BufferedinputStream in = null; try { final URL url = new URL(urlString); urlConnection = (httpURLConnection) url.openConnection(); in = new BufferedinputStream(urlConnection.getinputStream(),8 * 1024); out = new bufferedoutputstream(outputStream,8 * 1024); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (final IOException e) { e.printstacktrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (final IOException e) { e.printstacktrace(); } } return false; } }}
MainActivity
/** * 照片墙主活动,使用GrIDVIEw展示照片墙。 * * */public class MainActivity extends Activity { /** * 用于展示照片墙的GrIDVIEw */ private GrIDVIEw mPhotoWall; /** * GrIDVIEw的适配器 */ private ErJiHuanCun mAdapter; private int mImageThumbSize; private int mImageThumbSpacing; @OverrIDe protected voID onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVIEw(R.layout.activity_main); //mImageThumbSize = getResources().getDimensionPixelSize( // R.dimen.image_thumbnail_size); //mImageThumbSpacing = getResources().getDimensionPixelSize( // R.dimen.image_thumbnail_spacing); mPhotoWall = (GrIDVIEw) findVIEwByID(R.ID.photo_wall); mAdapter = new ErJiHuanCun(this,Images.imageThumbUrls,mPhotoWall); mPhotoWall.setAdapter(mAdapter);/* mPhotoWall.getVIEwTreeObserver().addOnGlobalLayoutListener( new VIEwTreeObserver.OnGlobalLayoutListener() { @OverrIDe public voID onGlobalLayout() { final int numColumns = (int) Math.floor(mPhotoWall .getWIDth() / (mImageThumbSize + mImageThumbSpacing)); if (numColumns > 0) { int columnWIDth = (mPhotoWall.getWIDth() / numColumns) - mImageThumbSpacing; mAdapter.setItemHeight(columnWIDth); mPhotoWall.getVIEwTreeObserver() .removeGlobalOnLayoutListener(this); } } });*/ } @OverrIDe protected voID onPause() { super.onPause(); //将缓存记录同步到journal文件中 mAdapter.flushCache(); } @OverrIDe protected voID onDestroy() { super.onDestroy(); // // 退出程序时结束所有的下载任务 mAdapter.cancelAllTasks(); }}
/** * 自定义正方形的ImageVIEw * */public class MyImageVIEw extends ImageVIEw { public MyImageVIEw(Context context,AttributeSet attrs,int defStyleAttr) { super(context,attrs,defStyleAttr); // Todo auto-generated constructor stub } public MyImageVIEw(Context context,AttributeSet attrs) { super(context,attrs); // Todo auto-generated constructor stub } public MyImageVIEw(Context context) { super(context); // Todo auto-generated constructor stub } @OverrIDeprotected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) { // Todo auto-generated method stub //将高度信息改成宽度即可 super.onMeasure(wIDthMeasureSpec,wIDthMeasureSpec);}}
主Activity的layout
<linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical" androID:padding="5dp" ><GrIDVIEw androID:ID="@+ID/photo_wall" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:gravity="center" androID:horizontalSpacing="5dp" androID:verticalSpacing="5dp" androID:numColumns="3" androID:stretchMode="columnWIDth" /></linearLayout>
GrIDVIEw中的Item ImageVIEw
<?xml version="1.0" enCoding="utf-8"?><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:orIEntation="vertical" ><com.example.imageloader.MyImageVIEw androID:layout_wIDth="match_parent" androID:layout_height="0dp" androID:ID="@+ID/photo" /></linearLayout>
图片压缩实现
public class ImageResizer { private static final String TAG="ImageResizer"; public static Bitmap decodeSampledBitmapFromresource(Resources res,int resID,int reqWIDth,int reqHeight){ final BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds=true; BitmapFactory.decodeResource(res,resID,options); options.inSampleSize=calculateInSampleSize(options,reqWIDth,reqHeight); options.inJustDecodeBounds=false; return BitmapFactory.decodeResource(res,options); } public static Bitmap decodeSampleBithmapFromfileDescriptor(fileDescriptor fd,int reqHeight){ final BitmapFactory.Options options=new BitmapFactory.Options(); options.inJustDecodeBounds=true; BitmapFactory.decodefileDescriptor(fd,null,reqHeight); options.inJustDecodeBounds=false; return BitmapFactory.decodefileDescriptor(fd,options); } public static int calculateInSampleSize(BitmapFactory.Options options,int reqHeight){ if(reqWIDth==0||reqHeight==0) return 1; final int wIDth=options.outWIDth; final int height=options.outHeight; int inSampleSize=1; if(height>reqHeight||wIDth>reqWIDth ){ final int halfheight=height/2; final int halfWIDth=wIDth/2; //尽最大限度的压缩图片,不能让图片的宽高比ImageVIEw的宽高小,否则在将 //图片显示到ImageVIEw时,图片会放大导致图片失真 while(halfheight/inSampleSize>reqHeight&&halfWIDth/inSampleSize>reqWIDth){ inSampleSize*=2; } } return inSampleSize; }}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的Android二级缓存加载图片实现照片墙功能全部内容,希望文章能够帮你解决Android二级缓存加载图片实现照片墙功能所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)