Android照片墙完整版,完美结合LruCache和DiskLruCache
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android照片墙完整版,完美结合LruCache和DiskLruCache相关的知识,希望对你有一定的参考价值。
转载地址:http://blog.csdn.net/guolin_blog/article/details/34093441#comments
在上一篇文章当中,我们学习了DiskLruCache的概念和基本用法,但仅仅是掌握理论知识显然是不够的,那么本篇文章我们就来继续进阶一下,看一看在实战当中应该怎样合理使用DiskLruCache。还不熟悉DiskLruCache用法的朋友可以先去参考我的上一篇文章 Android DiskLruCache完全解析,硬盘缓存的最佳方案 。
其实,在真正的项目实战当中如果仅仅是使用硬盘缓存的话,程序是有明显短板的。而如果只使用内存缓存的话,程序当然也会有很大的缺陷。因此,一个优秀的程序必然会将内存缓存和硬盘缓存结合到一起使用,那么本篇文章我们就来看一看,如何才能将LruCache和DiskLruCache完美结合到一起。
在 Android照片墙应用实现,再多的图片也不怕崩溃 这篇文章当中,我编写了一个照片墙的应用程序,但当时只是单纯使用到了内存缓存而已,而今天我们就对这个例子进行扩展,制作一个完整版的照片墙。
那我们开始动手吧,新建一个android项目,起名叫PhotoWallDemo,这里我使用的是Android 4.0的API。然后新建一个libcore.io包,并将DiskLruCache.java文件拷贝到这个包下,这样就把准备工作完成了。
接下来首先需要考虑的仍然是图片源的问题,简单起见,我仍然是吧所有图片都上传到了我的CSDN相册当中,然后新建一个Images类,将所有相册中图片的网址都配置进去,代码如下所示:
- public class Images {
- public final static String[] imageThumbUrls = new String[] {
- "http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg",
- "http://img.my.csdn.net/uploads/201407/26/1406382765_7341.jpg"
- };
- }
设置好了图片源之后,我们需要一个GridView来展示照片墙上的每一张图片。打开或修改activity_main.xml中的代码,如下所示:
- <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" >
- <GridView
- android:id="@+id/photo_wall"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:columnWidth="@dimen/image_thumbnail_size"
- android:gravity="center"
- android:horizontalSpacing="@dimen/image_thumbnail_spacing"
- android:numColumns="auto_fit"
- android:stretchMode="columnWidth"
- android:verticalSpacing="@dimen/image_thumbnail_spacing" >
- </GridView>
- </LinearLayout>
很简单,只是在LinearLayout中写了一个GridView而已。接着我们要定义GridView中每一个子View的布局,新建一个photo_layout.xml布局,加入如下代码:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" >
- <ImageView
- android:id="@+id/photo"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_centerInParent="true"
- android:scaleType="fitXY"
- />
- </RelativeLayout>
仍然很简单,photo_layout.xml布局中只有一个ImageView控件,就是用它来显示图片的。这样我们就把所有的布局文件都写好了。
接下来新建PhotoWallAdapter做为GridView的适配器,代码如下所示:
- public class PhotoWallAdapter extends ArrayAdapter<String> {
- /**
- * 记录所有正在下载或等待下载的任务。
- */
- private Set<BitmapWorkerTask> taskCollection;
- /**
- * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
- */
- private LruCache<String, Bitmap> mMemoryCache;
- /**
- * 图片硬盘缓存核心类。
- */
- private DiskLruCache mDiskLruCache;
- /**
- * GridView的实例
- */
- private GridView mPhotoWall;
- /**
- * 记录每个子项的高度。
- */
- private int mItemHeight = 0;
- public PhotoWallAdapter(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.empty_photo);
- 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 fluchCache() {
- 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();
- }
- /**
- * 异步下载图片的任务。
- *
- * @author guolin
- */
- 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);
- }
- 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对象
- */
- &nbs
以上是关于Android照片墙完整版,完美结合LruCache和DiskLruCache的主要内容,如果未能解决你的问题,请参考以下文章
Cordova fileTransfer 在 iOS 上完美运行,在 Android 上抛出错误代码 = 1