转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/34093441

在上一篇文章其中,我们学习了DiskLruCache的概念和基本使用方法。但仅仅是掌握理论知识显然是不够的,那么本篇文章我们就来继续进阶一下。看一看在实战其中应该如何合理使用DiskLruCache。

还不熟悉DiskLruCache使用方法的朋友能够先去參考我的上一篇文章 Android DiskLruCache全然解析,硬盘缓存的最佳方案 。

事实上,在真正的项目实战其中假设仅仅是使用硬盘缓存的话,程序是有明显短板的。而假设仅仅使用内存缓存的话,程序当然也会有非常大的缺陷。因此,一个优秀的程序必定会将内存缓存和硬盘缓存结合到一起使用,那么本篇文章我们就来看一看,如何才干将LruCache和DiskLruCache完美结合到一起。

Android照片墙应用实现,再多的图片也不怕崩溃 这篇文章其中,我编写了一个照片墙的应用程序,但当时仅仅是单纯使用到了内存缓存而已,而今天我们就对这个样例进行扩展,制作一个完整版的照片墙。

那我们開始动手吧。新建一个Android项目,起名叫PhotoWallDemo。这里我使用的是Android 4.0的API。

然后新建一个libcore.io包。并将DiskLruCache.java文件复制到这个包下。这样就把准备工作完毕了。

接下来首先须要考虑的仍然是图片源的问题,简单起见。我仍然是吧全部图片都上传到了我的CSDN相冊其中,然后新建一个Images类,将全部相冊中图片的网址都配置进去。代码例如以下所看到的:

  1. public class Images {
  2.  
  3. public final static String[] imageThumbUrls = new String[] {
  4. "http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg",
  5. "http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg",
  6. "http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg",
  7. "http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg",
  8. "http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg",
  9. "http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg",
  10. "http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg",
  11. "http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg",
  12. "http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg",
  13. "http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg",
  14. "http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg",
  15. "http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg",
  16. "http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg",
  17. "http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg",
  18. "http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg",
  19. "http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg",
  20. "http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg",
  21. "http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg",
  22. "http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg",
  23. "http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg",
  24. "http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg",
  25. "http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg",
  26. "http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg",
  27. "http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg",
  28. "http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg",
  29. "http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg",
  30. "http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg",
  31. "http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg",
  32. "http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg",
  33. "http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg",
  34. "http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg",
  35. "http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg",
  36. "http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg",
  37. "http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg",
  38. "http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg",
  39. "http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg",
  40. "http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg",
  41. "http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg",
  42. "http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg",
  43. "http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg",
  44. "http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg",
  45. "http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg",
  46. "http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg",
  47. "http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg",
  48. "http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg",
  49. "http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg",
  50. "http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg",
  51. "http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg",
  52. "http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg",
  53. "http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg",
  54. "http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg",
  55. "http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg",
  56. "http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg",
  57. "http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg",
  58. "http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg",
  59. "http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg",
  60. "http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg",
  61. "http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg",
  62. "http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg",
  63. "http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg",
  64. "http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg",
  65. "http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg",
  66. "http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg",
  67. "http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg",
  68. "http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg",
  69. "http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg",
  70. "http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg",
  71. "http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg",
  72. "http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg",
  73. "http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg",
  74. "http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg",
  75. "http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg",
  76. "http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg",
  77. "http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg",
  78. "http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg",
  79. "http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg",
  80. "http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg",
  81. "http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg",
  82. "http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg",
  83. "http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg",
  84. "http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg",
  85. "http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg",
  86. "http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg",
  87. "http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg",
  88. "http://img.my.csdn.net/uploads/201407/26/1406382765_7341.jpg"
  89. };
  90. }

设置好了图片源之后,我们须要一个GridView来展示照片墙上的每一张图片。

打开或改动activity_main.xml中的代码。例如以下所看到的:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent" >
  5.  
  6. <GridView
  7. android:id="@+id/photo_wall"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"
  10. android:columnWidth="@dimen/image_thumbnail_size"
  11. android:gravity="center"
  12. android:horizontalSpacing="@dimen/image_thumbnail_spacing"
  13. android:numColumns="auto_fit"
  14. android:stretchMode="columnWidth"
  15. android:verticalSpacing="@dimen/image_thumbnail_spacing" >
  16. </GridView>
  17.  
  18. </LinearLayout>

非常easy,仅仅是在LinearLayout中写了一个GridView而已。接着我们要定义GridView中每一个子View的布局,新建一个photo_layout.xml布局,加入例如以下代码:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content" >
  5.  
  6. <ImageView
  7. android:id="@+id/photo"
  8. android:layout_width="match_parent"
  9. android:layout_height="match_parent"
  10. android:layout_centerInParent="true"
  11. android:scaleType="fitXY"
  12. />
  13.  
  14. </RelativeLayout>

仍然非常easy,photo_layout.xml布局中仅仅有一个ImageView控件,就是用它来显示图片的。这样我们就把全部的布局文件都写好了。

接下来新建PhotoWallAdapter做为GridView的适配器,代码例如以下所看到的:

  1. public class PhotoWallAdapter extends ArrayAdapter<String> {
  2.  
  3. /**
  4. * 记录全部正在下载或等待下载的任务。
  5. */
  6. private Set<BitmapWorkerTask> taskCollection;
  7.  
  8. /**
  9. * 图片缓存技术的核心类。用于缓存全部下载好的图片,在程序内存达到设定值时会将最少近期使用的图片移除掉。
  10. */
  11. private LruCache<String, Bitmap> mMemoryCache;
  12.  
  13. /**
  14. * 图片硬盘缓存核心类。
  15. */
  16. private DiskLruCache mDiskLruCache;
  17.  
  18. /**
  19. * GridView的实例
  20. */
  21. private GridView mPhotoWall;
  22.  
  23. /**
  24. * 记录每一个子项的高度。
  25. */
  26. private int mItemHeight = 0;
  27.  
  28. public PhotoWallAdapter(Context context, int textViewResourceId, String[] objects,
  29. GridView photoWall) {
  30. super(context, textViewResourceId, objects);
  31. mPhotoWall = photoWall;
  32. taskCollection = new HashSet<BitmapWorkerTask>();
  33. // 获取应用程序最大可用内存
  34. int maxMemory = (int) Runtime.getRuntime().maxMemory();
  35. int cacheSize = maxMemory / 8;
  36. // 设置图片缓存大小为程序最大可用内存的1/8
  37. mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
  38. @Override
  39. protected int sizeOf(String key, Bitmap bitmap) {
  40. return bitmap.getByteCount();
  41. }
  42. };
  43. try {
  44. // 获取图片缓存路径
  45. File cacheDir = getDiskCacheDir(context, "thumb");
  46. if (!cacheDir.exists()) {
  47. cacheDir.mkdirs();
  48. }
  49. // 创建DiskLruCache实例,初始化缓存数据
  50. mDiskLruCache = DiskLruCache
  51. .open(cacheDir, getAppVersion(context), 1, 10 * 1024 * 1024);
  52. } catch (IOException e) {
  53. e.printStackTrace();
  54. }
  55. }
  56.  
  57. @Override
  58. public View getView(int position, View convertView, ViewGroup parent) {
  59. final String url = getItem(position);
  60. View view;
  61. if (convertView == null) {
  62. view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null);
  63. } else {
  64. view = convertView;
  65. }
  66. final ImageView imageView = (ImageView) view.findViewById(R.id.photo);
  67. if (imageView.getLayoutParams().height != mItemHeight) {
  68. imageView.getLayoutParams().height = mItemHeight;
  69. }
  70. // 给ImageView设置一个Tag,保证异步载入图片时不会乱序
  71. imageView.setTag(url);
  72. imageView.setImageResource(R.drawable.empty_photo);
  73. loadBitmaps(imageView, url);
  74. return view;
  75. }
  76.  
  77. /**
  78. * 将一张图片存储到LruCache中。
  79. *
  80. * @param key
  81. * LruCache的键。这里传入图片的URL地址。
  82.  
  83. * @param bitmap
  84. * LruCache的键。这里传入从网络上下载的Bitmap对象。
  85. */
  86. public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
  87. if (getBitmapFromMemoryCache(key) == null) {
  88. mMemoryCache.put(key, bitmap);
  89. }
  90. }
  91.  
  92. /**
  93. * 从LruCache中获取一张图片,假设不存在就返回null。
  94.  
  95. *
  96. * @param key
  97. * LruCache的键,这里传入图片的URL地址。
  98. * @return 相应传入键的Bitmap对象。或者null。
  99.  
  100. */
  101. public Bitmap getBitmapFromMemoryCache(String key) {
  102. return mMemoryCache.get(key);
  103. }
  104.  
  105. /**
  106. * 载入Bitmap对象。此方法会在LruCache中检查全部屏幕中可见的ImageView的Bitmap对象,
  107. * 假设发现不论什么一个ImageView的Bitmap对象不在缓存中。就会开启异步线程去下载图片。
  108. */
  109. public void loadBitmaps(ImageView imageView, String imageUrl) {
  110. try {
  111. Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);
  112. if (bitmap == null) {
  113. BitmapWorkerTask task = new BitmapWorkerTask();
  114. taskCollection.add(task);
  115. task.execute(imageUrl);
  116. } else {
  117. if (imageView != null && bitmap != null) {
  118. imageView.setImageBitmap(bitmap);
  119. }
  120. }
  121. } catch (Exception e) {
  122. e.printStackTrace();
  123. }
  124. }
  125.  
  126. /**
  127. * 取消全部正在下载或等待下载的任务。
  128. */
  129. public void cancelAllTasks() {
  130. if (taskCollection != null) {
  131. for (BitmapWorkerTask task : taskCollection) {
  132. task.cancel(false);
  133. }
  134. }
  135. }
  136.  
  137. /**
  138. * 依据传入的uniqueName获取硬盘缓存的路径地址。
  139. */
  140. public File getDiskCacheDir(Context context, String uniqueName) {
  141. String cachePath;
  142. if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
  143. || !Environment.isExternalStorageRemovable()) {
  144. cachePath = context.getExternalCacheDir().getPath();
  145. } else {
  146. cachePath = context.getCacheDir().getPath();
  147. }
  148. return new File(cachePath + File.separator + uniqueName);
  149. }
  150.  
  151. /**
  152. * 获取当前应用程序的版本。
  153. */
  154. public int getAppVersion(Context context) {
  155. try {
  156. PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(),
  157. 0);
  158. return info.versionCode;
  159. } catch (NameNotFoundException e) {
  160. e.printStackTrace();
  161. }
  162. return 1;
  163. }
  164.  
  165. /**
  166. * 设置item子项的高度。
  167. */
  168. public void setItemHeight(int height) {
  169. if (height == mItemHeight) {
  170. return;
  171. }
  172. mItemHeight = height;
  173. notifyDataSetChanged();
  174. }
  175.  
  176. /**
  177. * 使用MD5算法对传入的key进行加密并返回。
  178. */
  179. public String hashKeyForDisk(String key) {
  180. String cacheKey;
  181. try {
  182. final MessageDigest mDigest = MessageDigest.getInstance("MD5");
  183. mDigest.update(key.getBytes());
  184. cacheKey = bytesToHexString(mDigest.digest());
  185. } catch (NoSuchAlgorithmException e) {
  186. cacheKey = String.valueOf(key.hashCode());
  187. }
  188. return cacheKey;
  189. }
  190.  
  191. /**
  192. * 将缓存记录同步到journal文件里。
  193.  
  194. */
  195. public void fluchCache() {
  196. if (mDiskLruCache != null) {
  197. try {
  198. mDiskLruCache.flush();
  199. } catch (IOException e) {
  200. e.printStackTrace();
  201. }
  202. }
  203. }
  204.  
  205. private String bytesToHexString(byte[] bytes) {
  206. StringBuilder sb = new StringBuilder();
  207. for (int i = 0; i < bytes.length; i++) {
  208. String hex = Integer.toHexString(0xFF & bytes[i]);
  209. if (hex.length() == 1) {
  210. sb.append('0');
  211. }
  212. sb.append(hex);
  213. }
  214. return sb.toString();
  215. }
  216.  
  217. /**
  218. * 异步下载图片的任务。
  219.  
  220. *
  221. * @author guolin
  222. */
  223. class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
  224.  
  225. /**
  226. * 图片的URL地址
  227. */
  228. private String imageUrl;
  229.  
  230. @Override
  231. protected Bitmap doInBackground(String... params) {
  232. imageUrl = params[0];
  233. FileDescriptor fileDescriptor = null;
  234. FileInputStream fileInputStream = null;
  235. Snapshot snapShot = null;
  236. try {
  237. // 生成图片URL相应的key
  238. final String key = hashKeyForDisk(imageUrl);
  239. // 查找key相应的缓存
  240. snapShot = mDiskLruCache.get(key);
  241. if (snapShot == null) {
  242. // 假设没有找到相应的缓存。则准备从网络上请求数据,并写入缓存
  243. DiskLruCache.Editor editor = mDiskLruCache.edit(key);
  244. if (editor != null) {
  245. OutputStream outputStream = editor.newOutputStream(0);
  246. if (downloadUrlToStream(imageUrl, outputStream)) {
  247. editor.commit();
  248. } else {
  249. editor.abort();
  250. }
  251. }
  252. // 缓存被写入后,再次查找key相应的缓存
  253. snapShot = mDiskLruCache.get(key);
  254. }
  255. if (snapShot != null) {
  256. fileInputStream = (FileInputStream) snapShot.getInputStream(0);
  257. fileDescriptor = fileInputStream.getFD();
  258. }
  259. // 将缓存数据解析成Bitmap对象
  260. Bitmap bitmap = null;
  261. if (fileDescriptor != null) {
  262. bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
  263. }
  264. if (bitmap != null) {
  265. // 将Bitmap对象加入到内存缓存其中
  266. addBitmapToMemoryCache(params[0], bitmap);
  267. }
  268. return bitmap;
  269. } catch (IOException e) {
  270. e.printStackTrace();
  271. } finally {
  272. if (fileDescriptor == null && fileInputStream != null) {
  273. try {
  274. fileInputStream.close();
  275. } catch (IOException e) {
  276. }
  277. }
  278. }
  279. return null;
  280. }
  281.  
  282. @Override
  283. protected void onPostExecute(Bitmap bitmap) {
  284. super.onPostExecute(bitmap);
  285. // 依据Tag找到相应的ImageView控件。将下载好的图片显示出来。
  286.  
  287. ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);
  288. if (imageView != null && bitmap != null) {
  289. imageView.setImageBitmap(bitmap);
  290. }
  291. taskCollection.remove(this);
  292. }
  293.  
  294. /**
  295. * 建立HTTP请求,并获取Bitmap对象。
  296.  
  297. *
  298. * @param imageUrl
  299. * 图片的URL地址
  300. * @return 解析后的Bitmap对象
  301. */
  302. private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
  303. HttpURLConnection urlConnection = null;
  304. BufferedOutputStream out = null;
  305. BufferedInputStream in = null;
  306. try {
  307. final URL url = new URL(urlString);
  308. urlConnection = (HttpURLConnection) url.openConnection();
  309. in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
  310. out = new BufferedOutputStream(outputStream, 8 * 1024);
  311. int b;
  312. while ((b = in.read()) != -1) {
  313. out.write(b);
  314. }
  315. return true;
  316. } catch (final IOException e) {
  317. e.printStackTrace();
  318. } finally {
  319. if (urlConnection != null) {
  320. urlConnection.disconnect();
  321. }
  322. try {
  323. if (out != null) {
  324. out.close();
  325. }
  326. if (in != null) {
  327. in.close();
  328. }
  329. } catch (final IOException e) {
  330. e.printStackTrace();
  331. }
  332. }
  333. return false;
  334. }
  335.  
  336. }
  337.  
  338. }

代码有点长。我们一点点进行分析。

首先在PhotoWallAdapter的构造函数中,我们初始化了LruCache类。并设置了内存缓存容量为程序最大可用内存的1/8。紧接着调用了DiskLruCache的open()方法来创建实例。并设置了硬盘缓存容量为10M。这样我们就把LruCache和DiskLruCache的初始化工作完毕了。

接着在getView()方法中,我们为每一个ImageView设置了一个唯一的Tag,这个Tag的作用是为了后面能够准确地找回这个ImageView,不然异步载入图片会出现乱序的情况。然后在getView()方法的最后调用了loadBitmaps()方法,载入图片的详细逻辑也就是在这里运行的了。

进入到loadBitmaps()方法中能够看到,实现是调用了getBitmapFromMemoryCache()方法来从内存中获取缓存,假设获取到了则直接调用ImageView的setImageBitmap()方法将图片显示到界面上。假设内存中没有获取到。则开启一个BitmapWorkerTask任务来去异步载入图片。

那么在BitmapWorkerTask的doInBackground()方法中。我们就灵活运用了上篇文章中学习的DiskLruCache的各种使用方法。首先依据图片的URL生成相应的MD5 key。然后调用DiskLruCache的get()方法来获取硬盘缓存。假设没有获取到的话则从网络上请求图片并写入硬盘缓存,接着将Bitmap对象解析出来并加入到内存缓存其中,最后将这个Bitmap对象显示到界面上,这样一个完整的流程就运行完了。

那么我们再来分析一下上述流程。每次载入图片的时候都优先去内存缓存其中读取,当读取不到的时候则回去硬盘缓存中读取,而假设硬盘缓存仍然读取不到的话,就从网络上请求原始数据。

无论是从硬盘缓存还是从网络获取,读取到了数据之后都应该加入到内存缓存其中。这种话我们下次再去读取图片的时候就能迅速从内存其中读取到,而假设该图片从内存中被移除了的话,那就反复再运行一遍上述流程就能够了。

这样我们就把LruCache和DiskLruCache完美结合到一起了。接下来还须要编写MainActivity的代码,非常easy。例如以下所看到的:

  1. public class MainActivity extends Activity {
  2.  
  3. /**
  4. * 用于展示照片墙的GridView
  5. */
  6. private GridView mPhotoWall;
  7.  
  8. /**
  9. * GridView的适配器
  10. */
  11. private PhotoWallAdapter mAdapter;
  12.  
  13. private int mImageThumbSize;
  14. private int mImageThumbSpacing;
  15.  
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20. mImageThumbSize = getResources().getDimensionPixelSize(
  21. R.dimen.image_thumbnail_size);
  22. mImageThumbSpacing = getResources().getDimensionPixelSize(
  23. R.dimen.image_thumbnail_spacing);
  24. mPhotoWall = (GridView) findViewById(R.id.photo_wall);
  25. mAdapter = new PhotoWallAdapter(this, 0, Images.imageThumbUrls,
  26. mPhotoWall);
  27. mPhotoWall.setAdapter(mAdapter);
  28. mPhotoWall.getViewTreeObserver().addOnGlobalLayoutListener(
  29. new ViewTreeObserver.OnGlobalLayoutListener() {
  30.  
  31. @Override
  32. public void onGlobalLayout() {
  33. final int numColumns = (int) Math.floor(mPhotoWall
  34. .getWidth()
  35. / (mImageThumbSize + mImageThumbSpacing));
  36. if (numColumns > 0) {
  37. int columnWidth = (mPhotoWall.getWidth() / numColumns)
  38. - mImageThumbSpacing;
  39. mAdapter.setItemHeight(columnWidth);
  40. mPhotoWall.getViewTreeObserver()
  41. .removeGlobalOnLayoutListener(this);
  42. }
  43. }
  44. });
  45. }
  46.  
  47. @Override
  48. protected void onPause() {
  49. super.onPause();
  50. mAdapter.fluchCache();
  51. }
  52.  
  53. @Override
  54. protected void onDestroy() {
  55. super.onDestroy();
  56. // 退出程序时结束全部的下载任务
  57. mAdapter.cancelAllTasks();
  58. }
  59.  
  60. }

上述代码中,我们通过getViewTreeObserver()的方式监听View的布局事件,当布局完毕以后。我们又一次改动一下GridView中子View的高度,以保证子View的宽度和高度能够保持一致。

到这里还没有结束,最后还须要配置一下AndroidManifest.xml文件,并加入相应的权限。例如以下所看到的:

  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2. package="com.example.photoswalldemo"
  3. android:versionCode="1"
  4. android:versionName="1.0" >
  5.  
  6. <uses-sdk
  7. android:minSdkVersion="14"
  8. android:targetSdkVersion="17" />
  9.  
  10. <uses-permission android:name="android.permission.INTERNET" />
  11. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  12.  
  13. <application
  14. android:allowBackup="true"
  15. android:icon="@drawable/ic_launcher"
  16. android:label="@string/app_name"
  17. android:theme="@style/AppTheme" >
  18. <activity
  19. android:name="com.example.photoswalldemo.MainActivity"
  20. android:label="@string/app_name" >
  21. <intent-filter>
  22. <action android:name="android.intent.action.MAIN" />
  23. <category android:name="android.intent.category.LAUNCHER" />
  24. </intent-filter>
  25. </activity>
  26. </application>
  27.  
  28. </manifest>

好了。全部代码都在这儿了,让我们来运行一下吧。效果例如以下图所看到的:

第一次从网络上请求图片的时候有点慢,但之后载入图片就会非常快了。滑动起来也非常流畅。

那么我们最后再检查一下这些图片是不是已经正确缓存在指定地址了。进入 /sdcard/Android/data/<application package>/cache/thumb 这个路径,例如以下图所看到的:

能够看到。每张图片的缓存以及journal文件都在这里了,说明我们的硬盘缓存已经成功了。

好了,今天的解说就到这里,有疑问的朋友能够在以下留言。

源代码下载,请点击这里

第一时间获得博客更新提醒,以及很多其它技术信息分享,欢迎关注我的微信公众号。扫一扫下方二维码或搜索微信号guolin_blog,就可以关注。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

Android照片墙完整版,的完美结合LruCache和DiskLruCache的更多相关文章

  1. Android照片墙完整版,完美结合LruCache和DiskLruCache

    转载地址:http://blog.csdn.net/guolin_blog/article/details/34093441#comments 在上一篇文章当中,我们学习了DiskLruCache的概 ...

  2. Android照片墙完整版,完美结合 内存方案 LruCache 和 硬盘方案 DiskLruCache

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/34093441 在上一篇文章当中,我们学习了DiskLruCache的概念和基本用法 ...

  3. Android studio 升级,不用下载完整版,完美更新到2.0

    Android studio 2.0 公布已有一旦时间,据说,速度大大提高了.但是一直没有尝试更新,看到大家相继更新,所以迫不及待就准备更新,但是.更新之路确实异常坎坷.询问度娘,千奇百怪的问题接憧而 ...

  4. 将 FFmpeg 移植到 Android平台 (完整版)

    首先需要去FFmpeg的官网http://www.ffmpeg.org/去下载FFmpeg的源码,目前的版本号为FFmpeg3.3(Hilbert). 下载的文件为压缩包,解压后得到ffmpeg-3. ...

  5. Android版的菜谱客户端应用源码完整版

    Android版的菜谱客户端应用源码完整版,这个文章是从安卓教程网转载过来的,不是本人的原创,希望能够帮到大家的学习吧. <ignore_js_op> 152936qc7jdnv6vo0c ...

  6. 安卓开发笔记——关于照片墙的实现(完美缓存策略LruCache+DiskLruCache)

    这几天一直研究在安卓开发中图片应该如何处理,在网上翻了好多资料,这里做点小总结,如果朋友们有更好的解决方案,可以留言一起交流下. 内存缓存技术 在我们开发程序中要在界面上加载一张图片是件非常容易的事情 ...

  7. 爱拼图游戏android源码完整版

    这个是一款爱拼图游戏源码完整版,该游戏源码比较完整的,可以支持音乐的播放在游戏的玩的过程中,还可以控制系统的声音等,可以支持多种图片的选择来进行玩的,还可以根据自己的爱好选择不同的难度来的,级别分为: ...

  8. android应用商店完整版源码

    这个是从一个安卓学习的网站上转载过来的,android应用商店完整版源码,大家可以看看一下吧. _op><ignore_js_op> <ignore_js_op>< ...

  9. Android版的疯狂猜图游戏源码完整版分享

    这个游戏源码是在安装教程网那么分享过来的,Android版的疯狂猜图游戏源码完整版分享,也是本人之前很早以前发的一款游戏源码的,大家如果想了解一下,可以看看吧,不说多了,上一个图先吧.   > ...

随机推荐

  1. 当装了两个tomcat后,如何修改tomcat端口

    链接地址:http://blog.csdn.net/alongwilliam/article/details/8199974 以前只知道当tomcat端口号冲突了如何修改tomcat默认的8080端口 ...

  2. Eclipse用法和技巧十九:eclipse修改workspace

    工作中某一个项目的文件一般都在某一个路径,大多数人都习惯固定eclipse的workspace.不过偶尔也有点别的,比如做一个大项目中穿插着做些OJ,或者别的……这个时候当然可以选择在安装一个ecli ...

  3. android5.0(Lollipop) BLE Central牛刀小试

    转载请表明作者:http://blog.csdn.net/lansefeiyang08/article/details/46482073 昨天写了android L BLE Peripheral的简单 ...

  4. scrum经验

    Scrum是基于过程控制理论的经验方法,倡导自组织团队:其运行框架核心是迭代增量型并行开发,也是“适应性”的软件开发方法.Scrum提供了高度可视化的用于管理软件开发复杂性管理的敏捷项目管理的实践框架 ...

  5. ASP.NET - 使用 Eval() 绑定数据时使用 三元运算符

    ASP.NET邦定数据“<%#Eval("Sex")%>”运用三元运算符: <%#(Eval("Sex", "{0}") ...

  6. POJ 1955 Rubik's Cube

    暴力模拟就好了.... vim写代码真费事,手都写酸了... Rubik's Cube Time Limit: 1000MS   Memory Limit: 30000K Total Submissi ...

  7. Custom draw 和 Owner draw 的区别

    "Custom Draw" is a feature shared by all of Microsoft's common controls, which allows you ...

  8. 如何将excel文件中的数百万条数据在1分钟内导入数据库?

    在MYSQL里面,使用load data infile 命令就可以了. 步骤很简单 1.先将excel另存为csv格式的文本,csv是以逗号分隔各个字段数据的 2.在mysql中输入sql语句 loa ...

  9. OWAP Top 10

    2013 Top 10 List   A1-Injection Injection flaws, such as SQL, OS, and LDAP injection occur when untr ...

  10. ScaleAnimation类:尺寸变化动画类

    9.4  ScaleAnimation类:尺寸变化动画类 ScaleAnimation类是Android系统中的尺寸变化动画类,用于控制View对象的尺寸变化,该类继承于Animation类.Scal ...