Android编程之图片(异步)加载类

应某人之请,写一篇关于图片加载类。其实,网上有很多这样的类,而且比较推崇的是来自google中开源中的一篇。他写的比较好了,而且注意了内存优化,下面贴出它的图片下载类:

[java] view plaincopy

  1. /*
  2. * Copyright (C) 2010 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. *      http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.example.android.imagedownloader;
  17. import org.apache.http.HttpEntity;
  18. import org.apache.http.HttpResponse;
  19. import org.apache.http.HttpStatus;
  20. import org.apache.http.client.HttpClient;
  21. import org.apache.http.client.methods.HttpGet;
  22. import org.apache.http.impl.client.DefaultHttpClient;
  23. import android.graphics.Bitmap;
  24. import android.graphics.BitmapFactory;
  25. import android.graphics.Color;
  26. import android.graphics.drawable.ColorDrawable;
  27. import android.graphics.drawable.Drawable;
  28. import android.net.http.AndroidHttpClient;
  29. import android.os.AsyncTask;
  30. import android.os.Handler;
  31. import android.util.Log;
  32. import android.widget.ImageView;
  33. import java.io.FilterInputStream;
  34. import java.io.IOException;
  35. import java.io.InputStream;
  36. import java.lang.ref.SoftReference;
  37. import java.lang.ref.WeakReference;
  38. import java.util.HashMap;
  39. import java.util.LinkedHashMap;
  40. import java.util.concurrent.ConcurrentHashMap;
  41. /**
  42. * This helper class download images from the Internet and binds those with the provided ImageView.
  43. *
  44. * <p>It requires the INTERNET permission, which should be added to your application‘s manifest
  45. * file.</p>
  46. *
  47. * A local cache of downloaded images is maintained internally to improve performance.
  48. */
  49. public class ImageDownloader {
  50. private static final String LOG_TAG = "ImageDownloader";
  51. public enum Mode { NO_ASYNC_TASK, NO_DOWNLOADED_DRAWABLE, CORRECT }
  52. private Mode mode = Mode.NO_ASYNC_TASK;
  53. /**
  54. * Download the specified image from the Internet and binds it to the provided ImageView. The
  55. * binding is immediate if the image is found in the cache and will be done asynchronously
  56. * otherwise. A null bitmap will be associated to the ImageView if an error occurs.
  57. *
  58. * @param url The URL of the image to download.
  59. * @param imageView The ImageView to bind the downloaded image to.
  60. */
  61. public void download(String url, ImageView imageView) {
  62. resetPurgeTimer();
  63. Bitmap bitmap = getBitmapFromCache(url);
  64. if (bitmap == null) {
  65. forceDownload(url, imageView);
  66. } else {
  67. cancelPotentialDownload(url, imageView);
  68. imageView.setImageBitmap(bitmap);
  69. }
  70. }
  71. /*
  72. * Same as download but the image is always downloaded and the cache is not used.
  73. * Kept private at the moment as its interest is not clear.
  74. private void forceDownload(String url, ImageView view) {
  75. forceDownload(url, view, null);
  76. }
  77. */
  78. /**
  79. * Same as download but the image is always downloaded and the cache is not used.
  80. * Kept private at the moment as its interest is not clear.
  81. */
  82. private void forceDownload(String url, ImageView imageView) {
  83. // State sanity: url is guaranteed to never be null in DownloadedDrawable and cache keys.
  84. if (url == null) {
  85. imageView.setImageDrawable(null);
  86. return;
  87. }
  88. if (cancelPotentialDownload(url, imageView)) {
  89. switch (mode) {
  90. case NO_ASYNC_TASK:
  91. Bitmap bitmap = downloadBitmap(url);
  92. addBitmapToCache(url, bitmap);
  93. imageView.setImageBitmap(bitmap);
  94. break;
  95. case NO_DOWNLOADED_DRAWABLE:
  96. imageView.setMinimumHeight(156);
  97. BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
  98. task.execute(url);
  99. break;
  100. case CORRECT:
  101. task = new BitmapDownloaderTask(imageView);
  102. DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
  103. imageView.setImageDrawable(downloadedDrawable);
  104. imageView.setMinimumHeight(156);
  105. task.execute(url);
  106. break;
  107. }
  108. }
  109. }
  110. /**
  111. * Returns true if the current download has been canceled or if there was no download in
  112. * progress on this image view.
  113. * Returns false if the download in progress deals with the same url. The download is not
  114. * stopped in that case.
  115. */
  116. private static boolean cancelPotentialDownload(String url, ImageView imageView) {
  117. BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
  118. if (bitmapDownloaderTask != null) {
  119. String bitmapUrl = bitmapDownloaderTask.url;
  120. if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
  121. bitmapDownloaderTask.cancel(true);
  122. } else {
  123. // The same URL is already being downloaded.
  124. return false;
  125. }
  126. }
  127. return true;
  128. }
  129. /**
  130. * @param imageView Any imageView
  131. * @return Retrieve the currently active download task (if any) associated with this imageView.
  132. * null if there is no such task.
  133. */
  134. private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
  135. if (imageView != null) {
  136. Drawable drawable = imageView.getDrawable();
  137. if (drawable instanceof DownloadedDrawable) {
  138. DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
  139. return downloadedDrawable.getBitmapDownloaderTask();
  140. }
  141. }
  142. return null;
  143. }
  144. Bitmap downloadBitmap(String url) {
  145. final int IO_BUFFER_SIZE = 4 * 1024;
  146. // AndroidHttpClient is not allowed to be used from the main thread
  147. final HttpClient client = (mode == Mode.NO_ASYNC_TASK) ? new DefaultHttpClient() :
  148. AndroidHttpClient.newInstance("Android");
  149. final HttpGet getRequest = new HttpGet(url);
  150. try {
  151. HttpResponse response = client.execute(getRequest);
  152. final int statusCode = response.getStatusLine().getStatusCode();
  153. if (statusCode != HttpStatus.SC_OK) {
  154. Log.w("ImageDownloader", "Error " + statusCode +
  155. " while retrieving bitmap from " + url);
  156. return null;
  157. }
  158. final HttpEntity entity = response.getEntity();
  159. if (entity != null) {
  160. InputStream inputStream = null;
  161. try {
  162. inputStream = entity.getContent();
  163. // return BitmapFactory.decodeStream(inputStream);
  164. // Bug on slow connections, fixed in future release.
  165. return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
  166. } finally {
  167. if (inputStream != null) {
  168. inputStream.close();
  169. }
  170. entity.consumeContent();
  171. }
  172. }
  173. } catch (IOException e) {
  174. getRequest.abort();
  175. Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
  176. } catch (IllegalStateException e) {
  177. getRequest.abort();
  178. Log.w(LOG_TAG, "Incorrect URL: " + url);
  179. } catch (Exception e) {
  180. getRequest.abort();
  181. Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
  182. } finally {
  183. if ((client instanceof AndroidHttpClient)) {
  184. ((AndroidHttpClient) client).close();
  185. }
  186. }
  187. return null;
  188. }
  189. /*
  190. * An InputStream that skips the exact number of bytes provided, unless it reaches EOF.
  191. */
  192. static class FlushedInputStream extends FilterInputStream {
  193. public FlushedInputStream(InputStream inputStream) {
  194. super(inputStream);
  195. }
  196. @Override
  197. public long skip(long n) throws IOException {
  198. long totalBytesSkipped = 0L;
  199. while (totalBytesSkipped < n) {
  200. long bytesSkipped = in.skip(n - totalBytesSkipped);
  201. if (bytesSkipped == 0L) {
  202. int b = read();
  203. if (b < 0) {
  204. break;  // we reached EOF
  205. } else {
  206. bytesSkipped = 1; // we read one byte
  207. }
  208. }
  209. totalBytesSkipped += bytesSkipped;
  210. }
  211. return totalBytesSkipped;
  212. }
  213. }
  214. /**
  215. * The actual AsyncTask that will asynchronously download the image.
  216. */
  217. class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
  218. private String url;
  219. private final WeakReference<ImageView> imageViewReference;
  220. public BitmapDownloaderTask(ImageView imageView) {
  221. imageViewReference = new WeakReference<ImageView>(imageView);
  222. }
  223. /**
  224. * Actual download method.
  225. */
  226. @Override
  227. protected Bitmap doInBackground(String... params) {
  228. url = params[0];
  229. return downloadBitmap(url);
  230. }
  231. /**
  232. * Once the image is downloaded, associates it to the imageView
  233. */
  234. @Override
  235. protected void onPostExecute(Bitmap bitmap) {
  236. if (isCancelled()) {
  237. bitmap = null;
  238. }
  239. addBitmapToCache(url, bitmap);
  240. if (imageViewReference != null) {
  241. ImageView imageView = imageViewReference.get();
  242. BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
  243. // Change bitmap only if this process is still associated with it
  244. // Or if we don‘t use any bitmap to task association (NO_DOWNLOADED_DRAWABLE mode)
  245. if ((this == bitmapDownloaderTask) || (mode != Mode.CORRECT)) {
  246. imageView.setImageBitmap(bitmap);
  247. }
  248. }
  249. }
  250. }
  251. /**
  252. * A fake Drawable that will be attached to the imageView while the download is in progress.
  253. *
  254. * <p>Contains a reference to the actual download task, so that a download task can be stopped
  255. * if a new binding is required, and makes sure that only the last started download process can
  256. * bind its result, independently of the download finish order.</p>
  257. */
  258. static class DownloadedDrawable extends ColorDrawable {
  259. private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
  260. public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
  261. super(Color.BLACK);
  262. bitmapDownloaderTaskReference =
  263. new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
  264. }
  265. public BitmapDownloaderTask getBitmapDownloaderTask() {
  266. return bitmapDownloaderTaskReference.get();
  267. }
  268. }
  269. public void setMode(Mode mode) {
  270. this.mode = mode;
  271. clearCache();
  272. }
  273. /*
  274. * Cache-related fields and methods.
  275. *
  276. * We use a hard and a soft cache. A soft reference cache is too aggressively cleared by the
  277. * Garbage Collector.
  278. */
  279. private static final int HARD_CACHE_CAPACITY = 10;
  280. private static final int DELAY_BEFORE_PURGE = 10 * 1000; // in milliseconds
  281. // Hard cache, with a fixed maximum capacity and a life duration
  282. private final HashMap<String, Bitmap> sHardBitmapCache =
  283. new LinkedHashMap<String, Bitmap>(HARD_CACHE_CAPACITY / 2, 0.75f, true) {
  284. @Override
  285. protected boolean removeEldestEntry(LinkedHashMap.Entry<String, Bitmap> eldest) {
  286. if (size() > HARD_CACHE_CAPACITY) {
  287. // Entries push-out of hard reference cache are transferred to soft reference cache
  288. sSoftBitmapCache.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
  289. return true;
  290. } else
  291. return false;
  292. }
  293. };
  294. // Soft cache for bitmaps kicked out of hard cache
  295. private final static ConcurrentHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache =
  296. new ConcurrentHashMap<String, SoftReference<Bitmap>>(HARD_CACHE_CAPACITY / 2);
  297. private final Handler purgeHandler = new Handler();
  298. private final Runnable purger = new Runnable() {
  299. public void run() {
  300. clearCache();
  301. }
  302. };
  303. /**
  304. * Adds this bitmap to the cache.
  305. * @param bitmap The newly downloaded bitmap.
  306. */
  307. private void addBitmapToCache(String url, Bitmap bitmap) {
  308. if (bitmap != null) {
  309. synchronized (sHardBitmapCache) {
  310. sHardBitmapCache.put(url, bitmap);
  311. }
  312. }
  313. }
  314. /**
  315. * @param url The URL of the image that will be retrieved from the cache.
  316. * @return The cached bitmap or null if it was not found.
  317. */
  318. private Bitmap getBitmapFromCache(String url) {
  319. // First try the hard reference cache
  320. synchronized (sHardBitmapCache) {
  321. final Bitmap bitmap = sHardBitmapCache.get(url);
  322. if (bitmap != null) {
  323. // Bitmap found in hard cache
  324. // Move element to first position, so that it is removed last
  325. sHardBitmapCache.remove(url);
  326. sHardBitmapCache.put(url, bitmap);
  327. return bitmap;
  328. }
  329. }
  330. // Then try the soft reference cache
  331. SoftReference<Bitmap> bitmapReference = sSoftBitmapCache.get(url);
  332. if (bitmapReference != null) {
  333. final Bitmap bitmap = bitmapReference.get();
  334. if (bitmap != null) {
  335. // Bitmap found in soft cache
  336. return bitmap;
  337. } else {
  338. // Soft reference has been Garbage Collected
  339. sSoftBitmapCache.remove(url);
  340. }
  341. }
  342. return null;
  343. }
  344. /**
  345. * Clears the image cache used internally to improve performance. Note that for memory
  346. * efficiency reasons, the cache will automatically be cleared after a certain inactivity delay.
  347. */
  348. public void clearCache() {
  349. sHardBitmapCache.clear();
  350. sSoftBitmapCache.clear();
  351. }
  352. /**
  353. * Allow a new delay before the automatic cache clear is done.
  354. */
  355. private void resetPurgeTimer() {
  356. purgeHandler.removeCallbacks(purger);
  357. purgeHandler.postDelayed(purger, DELAY_BEFORE_PURGE);
  358. }
  359. }

里面有一些图片加载的方式方法,都很可取,不过对于ListView的优化而言,还应配合列表滚动监听来写。也就是说,当列表停止滚动,手离开屏幕的时候,再加载大数据,例如图片。稍后,我也会整理一篇,给大家提供参考借鉴。

源代码来自:http://code.google.com/p/android-imagedownloader/

滚动加载的例子:http://www.iteye.com/topic/1118828

摘自:http://blog.csdn.net/xyz_fly/article/details/7864076

Android编程之图片(异步)加载类

时间: 2024-10-10 23:46:54

Android编程之图片(异步)加载类的相关文章

(转)Android技术积累:图片异步加载

当在ListView或GridView中要加载很多图片时,很容易出现滑动时的卡顿现象,以及出现OOM导致FC(Force Close). 会出现卡顿现象主要是因为加载数据慢,要等数据加载完才能显示出来.可以通过将数据分页显示,以及将耗时的图片加载用异步的方式和图片缓存,这样就可以解决卡顿的问题. 大部分开发者在ListView或GridView加载图片时,都会在getView方法里创建新的线程去异步加载图片.然而,当屏幕快速向下滑动时,每个划过的Item都会调用getView一次,即会创建出很多

Android图片异步加载之Android-Universal-Image-Loader

将近一个月没有更新博客了,由于这段时间以来准备毕业论文等各种事务缠身,一直没有时间和精力沉下来继续学习和整理一些东西.最近刚刚恢复到正轨,正好这两天看了下Android上关于图片异步加载的开源项目,就顺便整理记录下来,作为这一个多月来博客的重新开火做饭吧.从今天起我会陆续恢复博客的更新,也希望大家继续支持. 今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异

Android新浪微博客户端(七)——ListView中的图片异步加载、缓存

原文出自:方杰|http://fangjie.sinaapp.com/?p=193转载请注明出处 最终效果演示:http://fangjie.sinaapp.com/?page_id=54该项目代码已经放到github:https://github.com/JayFang1993/SinaWeibo 一.ListView的图片异步加载 我们都知道对每一个Weibo Item都有用户头像,而且每一条微博还可能带有图片.如果在加载列表的同时加载图片,这样有几个缺点,第一很费事,界面卡住,用户体验很不

简单的ListView中item图片异步加载

前言: 在android开发当中,从目标地址获取图片往往都是采用异步加载的方法.当完全加载完图片后在进行显示,也有些是直接将加载的图片一点一点的显示出来. 这两个区别只是对流的处理不同而已.现在就讲讲当图片被完全获取到后在显示的方法. 一,效果图:       初始化:                                                   获取后:                         1.1,效果思路: 初始化的时候默认ImageView显示一张白色的图

Android Asynchronous Http Client--Android 开源的网络异步加载类

整理Android Asynchronous Http Client的使用 Android Asynchronous Http Client(AHC) 一个回调式的Android网络请求库 概括: AHC是基于Apache的HttpClient 库,所有的网络请求过程在UI线程之外进行,而回调是在Handler里面处理.也可以再Service或者后台程序里面使用,这个库会自动识别并在相应的Context进行处理. 特点: 异步发送HTTP请求,在回调函数中处理响应 HTTP请求过程不在UI线程进

Android图片异步加载之Android-Universal-Image-Loader(转)

今天要介绍的是Github上一个使用非常广泛的图片异步加载库Android-Universal-Image-Loader,该项目的功能十分强大,可以说是我见过的目前功能最全.性能最优的图片异步加载解决方案.做Android的同学都知道,Android加载大量图片时,由于系统分配给图片加载的内存大小有限,所以,如果加载图片量非常大的话容易报OOM异常,关于这个异常已经有不少解决方案了,我就不赘述.下面就简要介绍下这个开源项目的主要功能和使用: 一.功能概要 多线程图片加载: 灵活更改ImageLo

Android消息处理机制:源码剖析Handler、Looper,并实现图片异步加载

引言 我们在做 Android 开发时,常常需要实现异步加载图片/网页/其他.事实上,要实现异步加载,就需要实现线程间通信,而在 Android 中结合使用 Handler.Looper.Message 能够让不同的线程通信,完成异步任务.虽然 Android 官方为我们提供了 AsyncTask 类来完成异步任务,但这个类存在许多问题,并不好用,而且,AsyncTask 也是通过 Handler 和 Thread 来实现异步加载的,所以学习这方面的知识是有必要的 本文讲解思路大致如下:绘制 A

Android图片异步加载

原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/Android-Universal-Image-Loader 开发Android程序,一般情况下都会有两个操作,图片的异步加载与缓存,而图片的异步加载大都是从网络读取图片(还有生成本地图片缩略图等操作),为了减少网络操作,加快图片加载速度就需要对图片进行缓存,所以网上的好多图片异步加载方法都是与图片的

自己动手写android图片异步加载库

尊重他人劳动成果,转载请说明出处:http://blog.csdn.net/bingospunky/article/details/44344085 接触android有半年了,关于图片异步加载,一直只用别人的框架,虽然特别方便,但是始终未见识到图片异步加载的庐山真面目.最近比较悠闲,研究一些高大上的东西.在这篇文章总结一下我对图片异步加载的一些学习心得. 图片加载最重要的无非就是内存和线程.大家都知道关于内存溢出一般的解决方案就是LruCache,在我的这个demo里我只要使用SoftRefe