Android异步加载网络图片

Android图片的异步加载,主要原理:

加载图片时先查看缓存中时候存在该图片,如果存在则返回该图片,否则先加载载一个默认的占位图片,同时创建一个通过网络获取图片的任务并添加,任务完成后放松消息给主线程更新界面。

使用方法:

[java] view plain copy

  1. AsynImageLoader asynImageLoader = new AsynImageLoader();
  2. asynImageLoader.showImageAsyn(imageView, imageUrl, resId);

类代码:

[java] view plain copy

  1. package com.wangge.uumao.http;
  2. import java.lang.ref.SoftReference;
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7. import android.graphics.Bitmap;
  8. import android.os.Handler;
  9. import android.os.Message;
  10. import android.util.Log;
  11. import android.widget.ImageView;
  12. import com.wangge.uumao.util.PicUtil;
  13. public class AsynImageLoader {
  14. private static final String TAG = "AsynImageLoader";
  15. // 缓存下载过的图片的Map
  16. private Map<String, SoftReference<Bitmap>> caches;
  17. // 任务队列
  18. private List<Task> taskQueue;
  19. private boolean isRunning = false;
  20. public AsynImageLoader(){
  21. // 初始化变量
  22. caches = new HashMap<String, SoftReference<Bitmap>>();
  23. taskQueue = new ArrayList<AsynImageLoader.Task>();
  24. // 启动图片下载线程
  25. isRunning = true;
  26. new Thread(runnable).start();
  27. }
  28. /**
  29. *
  30. * @param imageView 需要延迟加载图片的对象
  31. * @param url 图片的URL地址
  32. * @param resId 图片加载过程中显示的图片资源
  33. */
  34. public void showImageAsyn(ImageView imageView, String url, int resId){
  35. imageView.setTag(url);
  36. Bitmap bitmap = loadImageAsyn(url, getImageCallback(imageView, resId));
  37. if(bitmap == null){
  38. imageView.setImageResource(resId);
  39. }else{
  40. imageView.setImageBitmap(bitmap);
  41. }
  42. }
  43. public Bitmap loadImageAsyn(String path, ImageCallback callback){
  44. // 判断缓存中是否已经存在该图片
  45. if(caches.containsKey(path)){
  46. // 取出软引用
  47. SoftReference<Bitmap> rf = caches.get(path);
  48. // 通过软引用,获取图片
  49. Bitmap bitmap = rf.get();
  50. // 如果该图片已经被释放,则将该path对应的键从Map中移除掉
  51. if(bitmap == null){
  52. caches.remove(path);
  53. }else{
  54. // 如果图片未被释放,直接返回该图片
  55. Log.i(TAG, "return image in cache" + path);
  56. return bitmap;
  57. }
  58. }else{
  59. // 如果缓存中不常在该图片,则创建图片下载任务
  60. Task task = new Task();
  61. task.path = path;
  62. task.callback = callback;
  63. Log.i(TAG, "new Task ," + path);
  64. if(!taskQueue.contains(task)){
  65. taskQueue.add(task);
  66. // 唤醒任务下载队列
  67. synchronized (runnable) {
  68. runnable.notify();
  69. }
  70. }
  71. }
  72. // 缓存中没有图片则返回null
  73. return null;
  74. }
  75. /**
  76. *
  77. * @param imageView
  78. * @param resId 图片加载完成前显示的图片资源ID
  79. * @return
  80. */
  81. private ImageCallback getImageCallback(final ImageView imageView, final int resId){
  82. return new ImageCallback() {
  83. @Override
  84. public void loadImage(String path, Bitmap bitmap) {
  85. if(path.equals(imageView.getTag().toString())){
  86. imageView.setImageBitmap(bitmap);
  87. }else{
  88. imageView.setImageResource(resId);
  89. }
  90. }
  91. };
  92. }
  93. private Handler handler = new Handler(){
  94. @Override
  95. public void handleMessage(Message msg) {
  96. // 子线程中返回的下载完成的任务
  97. Task task = (Task)msg.obj;
  98. // 调用callback对象的loadImage方法,并将图片路径和图片回传给adapter
  99. task.callback.loadImage(task.path, task.bitmap);
  100. }
  101. };
  102. private Runnable runnable = new Runnable() {
  103. @Override
  104. public void run() {
  105. while(isRunning){
  106. // 当队列中还有未处理的任务时,执行下载任务
  107. while(taskQueue.size() > 0){
  108. // 获取第一个任务,并将之从任务队列中删除
  109. Task task = taskQueue.remove(0);
  110. // 将下载的图片添加到缓存
  111. task.bitmap = PicUtil.getbitmap(task.path);
  112. caches.put(task.path, new SoftReference<Bitmap>(task.bitmap));
  113. if(handler != null){
  114. // 创建消息对象,并将完成的任务添加到消息对象中
  115. Message msg = handler.obtainMessage();
  116. msg.obj = task;
  117. // 发送消息回主线程
  118. handler.sendMessage(msg);
  119. }
  120. }
  121. //如果队列为空,则令线程等待
  122. synchronized (this) {
  123. try {
  124. this.wait();
  125. } catch (InterruptedException e) {
  126. e.printStackTrace();
  127. }
  128. }
  129. }
  130. }
  131. };
  132. //回调接口
  133. public interface ImageCallback{
  134. void loadImage(String path, Bitmap bitmap);
  135. }
  136. class Task{
  137. // 下载任务的下载路径
  138. String path;
  139. // 下载的图片
  140. Bitmap bitmap;
  141. // 回调对象
  142. ImageCallback callback;
  143. @Override
  144. public boolean equals(Object o) {
  145. Task task = (Task)o;
  146. return task.path.equals(path);
  147. }
  148. }
  149. }

最后附上PicUtil类的代码,之前忘了贴这个类的代码,不好意识了~~

[java] view plain copy

  1. public class PicUtil {
  2. private static final String TAG = "PicUtil";
  3. /**
  4. * 根据一个网络连接(URL)获取bitmapDrawable图像
  5. *
  6. * @param imageUri
  7. * @return
  8. */
  9. public static BitmapDrawable getfriendicon(URL imageUri) {
  10. BitmapDrawable icon = null;
  11. try {
  12. HttpURLConnection hp = (HttpURLConnection) imageUri
  13. .openConnection();
  14. icon = new BitmapDrawable(hp.getInputStream());// 将输入流转换成bitmap
  15. hp.disconnect();// 关闭连接
  16. } catch (Exception e) {
  17. }
  18. return icon;
  19. }
  20. /**
  21. * 根据一个网络连接(String)获取bitmapDrawable图像
  22. *
  23. * @param imageUri
  24. * @return
  25. */
  26. public static BitmapDrawable getcontentPic(String imageUri) {
  27. URL imgUrl = null;
  28. try {
  29. imgUrl = new URL(imageUri);
  30. } catch (MalformedURLException e1) {
  31. e1.printStackTrace();
  32. }
  33. BitmapDrawable icon = null;
  34. try {
  35. HttpURLConnection hp = (HttpURLConnection) imgUrl.openConnection();
  36. icon = new BitmapDrawable(hp.getInputStream());// 将输入流转换成bitmap
  37. hp.disconnect();// 关闭连接
  38. } catch (Exception e) {
  39. }
  40. return icon;
  41. }
  42. /**
  43. * 根据一个网络连接(URL)获取bitmap图像
  44. *
  45. * @param imageUri
  46. * @return
  47. */
  48. public static Bitmap getusericon(URL imageUri) {
  49. // 显示网络上的图片
  50. URL myFileUrl = imageUri;
  51. Bitmap bitmap = null;
  52. try {
  53. HttpURLConnection conn = (HttpURLConnection) myFileUrl
  54. .openConnection();
  55. conn.setDoInput(true);
  56. conn.connect();
  57. InputStream is = conn.getInputStream();
  58. bitmap = BitmapFactory.decodeStream(is);
  59. is.close();
  60. } catch (IOException e) {
  61. e.printStackTrace();
  62. }
  63. return bitmap;
  64. }
  65. /**
  66. * 根据一个网络连接(String)获取bitmap图像
  67. *
  68. * @param imageUri
  69. * @return
  70. * @throws MalformedURLException
  71. */
  72. public static Bitmap getbitmap(String imageUri) {
  73. // 显示网络上的图片
  74. Bitmap bitmap = null;
  75. try {
  76. URL myFileUrl = new URL(imageUri);
  77. HttpURLConnection conn = (HttpURLConnection) myFileUrl
  78. .openConnection();
  79. conn.setDoInput(true);
  80. conn.connect();
  81. InputStream is = conn.getInputStream();
  82. bitmap = BitmapFactory.decodeStream(is);
  83. is.close();
  84. Log.i(TAG, "image download finished." + imageUri);
  85. } catch (IOException e) {
  86. e.printStackTrace();
  87. return null;
  88. }
  89. return bitmap;
  90. }
  91. /**
  92. * 下载图片 同时写道本地缓存文件中
  93. *
  94. * @param context
  95. * @param imageUri
  96. * @return
  97. * @throws MalformedURLException
  98. */
  99. public static Bitmap getbitmapAndwrite(String imageUri) {
  100. Bitmap bitmap = null;
  101. try {
  102. // 显示网络上的图片
  103. URL myFileUrl = new URL(imageUri);
  104. HttpURLConnection conn = (HttpURLConnection) myFileUrl
  105. .openConnection();
  106. conn.setDoInput(true);
  107. conn.connect();
  108. InputStream is = conn.getInputStream();
  109. File cacheFile = FileUtil.getCacheFile(imageUri);
  110. BufferedOutputStream bos = null;
  111. bos = new BufferedOutputStream(new FileOutputStream(cacheFile));
  112. Log.i(TAG, "write file to " + cacheFile.getCanonicalPath());
  113. byte[] buf = new byte[1024];
  114. int len = 0;
  115. // 将网络上的图片存储到本地
  116. while ((len = is.read(buf)) > 0) {
  117. bos.write(buf, 0, len);
  118. }
  119. is.close();
  120. bos.close();
  121. // 从本地加载图片
  122. bitmap = BitmapFactory.decodeFile(cacheFile.getCanonicalPath());
  123. String name = MD5Util.MD5(imageUri);
  124. } catch (IOException e) {
  125. e.printStackTrace();
  126. }
  127. return bitmap;
  128. }
  129. public static boolean downpic(String picName, Bitmap bitmap) {
  130. boolean nowbol = false;
  131. try {
  132. File saveFile = new File("/mnt/sdcard/download/weibopic/" + picName
  133. + ".png");
  134. if (!saveFile.exists()) {
  135. saveFile.createNewFile();
  136. }
  137. FileOutputStream saveFileOutputStream;
  138. saveFileOutputStream = new FileOutputStream(saveFile);
  139. nowbol = bitmap.compress(Bitmap.CompressFormat.PNG, 100,
  140. saveFileOutputStream);
  141. saveFileOutputStream.close();
  142. } catch (FileNotFoundException e) {
  143. e.printStackTrace();
  144. } catch (IOException e) {
  145. e.printStackTrace();
  146. } catch (Exception e) {
  147. e.printStackTrace();
  148. }
  149. return nowbol;
  150. }
  151. public static void writeTofiles(Context context, Bitmap bitmap,
  152. String filename) {
  153. BufferedOutputStream outputStream = null;
  154. try {
  155. outputStream = new BufferedOutputStream(context.openFileOutput(
  156. filename, Context.MODE_PRIVATE));
  157. bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
  158. } catch (FileNotFoundException e) {
  159. e.printStackTrace();
  160. }
  161. }
  162. /**
  163. * 将文件写入缓存系统中
  164. *
  165. * @param filename
  166. * @param is
  167. * @return
  168. */
  169. public static String writefile(Context context, String filename,
  170. InputStream is) {
  171. BufferedInputStream inputStream = null;
  172. BufferedOutputStream outputStream = null;
  173. try {
  174. inputStream = new BufferedInputStream(is);
  175. outputStream = new BufferedOutputStream(context.openFileOutput(
  176. filename, Context.MODE_PRIVATE));
  177. byte[] buffer = new byte[1024];
  178. int length;
  179. while ((length = inputStream.read(buffer)) != -1) {
  180. outputStream.write(buffer, 0, length);
  181. }
  182. } catch (Exception e) {
  183. } finally {
  184. if (inputStream != null) {
  185. try {
  186. inputStream.close();
  187. } catch (IOException e) {
  188. e.printStackTrace();
  189. }
  190. }
  191. if (outputStream != null) {
  192. try {
  193. outputStream.flush();
  194. outputStream.close();
  195. } catch (IOException e) {
  196. e.printStackTrace();
  197. }
  198. }
  199. }
  200. return context.getFilesDir() + "/" + filename + ".jpg";
  201. }
  202. // 放大缩小图片
  203. public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
  204. int width = bitmap.getWidth();
  205. int height = bitmap.getHeight();
  206. Matrix matrix = new Matrix();
  207. float scaleWidht = ((float) w / width);
  208. float scaleHeight = ((float) h / height);
  209. matrix.postScale(scaleWidht, scaleHeight);
  210. Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height,
  211. matrix, true);
  212. return newbmp;
  213. }
  214. // 将Drawable转化为Bitmap
  215. public static Bitmap drawableToBitmap(Drawable drawable) {
  216. int width = drawable.getIntrinsicWidth();
  217. int height = drawable.getIntrinsicHeight();
  218. Bitmap bitmap = Bitmap.createBitmap(width, height, drawable
  219. .getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
  220. : Bitmap.Config.RGB_565);
  221. Canvas canvas = new Canvas(bitmap);
  222. drawable.setBounds(0, 0, width, height);
  223. drawable.draw(canvas);
  224. return bitmap;
  225. }
  226. // 获得圆角图片的方法
  227. public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {
  228. if(bitmap == null){
  229. return null;
  230. }
  231. Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
  232. bitmap.getHeight(), Config.ARGB_8888);
  233. Canvas canvas = new Canvas(output);
  234. final int color = 0xff424242;
  235. final Paint paint = new Paint();
  236. final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
  237. final RectF rectF = new RectF(rect);
  238. paint.setAntiAlias(true);
  239. canvas.drawARGB(0, 0, 0, 0);
  240. paint.setColor(color);
  241. canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
  242. paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
  243. canvas.drawBitmap(bitmap, rect, rect, paint);
  244. return output;
  245. }
  246. // 获得带倒影的图片方法
  247. public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) {
  248. final int reflectionGap = 4;
  249. int width = bitmap.getWidth();
  250. int height = bitmap.getHeight();
  251. Matrix matrix = new Matrix();
  252. matrix.preScale(1, -1);
  253. Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height / 2,
  254. width, height / 2, matrix, false);
  255. Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
  256. (height + height / 2), Config.ARGB_8888);
  257. Canvas canvas = new Canvas(bitmapWithReflection);
  258. canvas.drawBitmap(bitmap, 0, 0, null);
  259. Paint deafalutPaint = new Paint();
  260. canvas.drawRect(0, height, width, height + reflectionGap, deafalutPaint);
  261. canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
  262. Paint paint = new Paint();
  263. LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
  264. bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,
  265. 0x00ffffff, TileMode.CLAMP);
  266. paint.setShader(shader);
  267. // Set the Transfer mode to be porter duff and destination in
  268. paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
  269. // Draw a rectangle using the paint with our linear gradient
  270. canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
  271. + reflectionGap, paint);
  272. return bitmapWithReflection;
  273. }
  274. }

FileUtil

[java] view plain copy

    1. package com.wangge.coupon.util;
    2. import java.io.File;
    3. import java.io.IOException;
    4. import android.os.Environment;
    5. import android.util.Log;
    6. import com.wangge.coupon.http.AsynImageLoader;
    7. public class FileUtil {
    8. private static final String TAG = "FileUtil";
    9. public static File getCacheFile(String imageUri){
    10. File cacheFile = null;
    11. try {
    12. if (Environment.getExternalStorageState().equals(
    13. Environment.MEDIA_MOUNTED)) {
    14. File sdCardDir = Environment.getExternalStorageDirectory();
    15. String fileName = getFileName(imageUri);
    16. File dir = new File(sdCardDir.getCanonicalPath()
    17. + AsynImageLoader.CACHE_DIR);
    18. if (!dir.exists()) {
    19. dir.mkdirs();
    20. }
    21. cacheFile = new File(dir, fileName);
    22. Log.i(TAG, "exists:" + cacheFile.exists() + ",dir:" + dir + ",file:" + fileName);
    23. }
    24. } catch (IOException e) {
    25. e.printStackTrace();
    26. Log.e(TAG, "getCacheFileError:" + e.getMessage());
    27. }
    28. return cacheFile;
    29. }
    30. public static String getFileName(String path) {
    31. int index = path.lastIndexOf("/");
    32. return path.substring(index + 1);
    33. }
    34. }
时间: 2025-01-05 10:48:16

Android异步加载网络图片的相关文章

Android 异步加载网络图片并缓存到本地

在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片. 软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地有没有,如果没有再从网络读取. 记得2月份在和爱奇艺公司的项目总监一起搞联通的OTT盒子的时候他就提了一下软引用,奇艺做的手机客户端就是采用这种方法,所以你会发现奇艺客户端占用很大的空间,下面就分享一下异步加载网络图片的方法吧. FileCache

Android之ListView异步加载网络图片(优化缓存机制)【转】

网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决.下面提出一些优化: 1.采用线程池 2.内存缓存+文件缓存 3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4.对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明.先放上内存缓存类的代码MemoryCache.java: public class MemoryCache { private static final String TAG = "MemoryCa

Android异步加载全解析之使用AsyncTask

Android异步加载全解析之使用AsyncTask 概述 既然前面提到了多线程,就不得不提到线程池,通过线程池,不仅可以对并发线程进行管理,更可以提高他们执行的效率,优化整个App.当然我们可以自己创建一个线程池,不过这样是很烦的,要创建一个高效的线程池还是挺费事的,不过,Android系统给我吗提供了AsyncTask这样一个类,来帮助我们快速实现多线程开发,它的底层实现,其实就是一个线程池. AsyncTask初探 AsyncTask,顾名思义就是用来做异步处理的.通过AsyncTask,

Android异步加载

Android异步加载 一.为什么要使用异步加载? 1.Android是单线程模型 2.耗时操作阻碍UI线程 二.异步加载最常用的两种方式 1.多线程.线程池 2.AsyncTask 三.实现ListView图文混排 3-1 实现读取网页中的json数据到ListView中 (图片首先为默认图片) 3.1.1:主布局只有一个ListView和一个listView_item的布局 3.1.2:网页json数据的链接(http://www.imooc.com/api/teacher?type=4&n

Android 异步加载

Android的Lazy Load主要体现在网络数据(图片)异步加载.数据库查询.复杂业务逻辑处理以及费时任务操作导致的异步处理等方面.在介绍Android开发过程中,异步处理这个常见的技术问题之前,我们简单回顾下Android开发过程中需要注意的几个地方. Android应用开发过程中必须遵循单线程模型(Single Thread Model)的原则.因为Android的UI操作并不是线程安全的,所以涉及UI的操作必须在UI线程中完成.但是并非所有的操作都能在主线程中进行,Google工程师在

Android 异步加载解决方案

Android的Lazy Load主要体现在网络数据(图片)异步加载.数据库查询.复杂业务逻辑处理以及费时任务操作导致的异步处理等方面.在介绍Android开发过程中,异步处理这个常见的技术问题之前,我们简单回顾下Android开发过程中需要注意的几个地方. Android应用开发过程中必须遵循单线程模型(Single Thread Model)的原则.因为Android的UI操作并不是线程安全的,所以涉及UI的操作必须在UI线程中完成.但是并非所有的操作都能在主线程中进行,Google工程师在

iOS开发swift版异步加载网络图片(带缓存和缺省图片)

iOS开发之swift版异步加载网络图片 与SDWebImage异步加载网络图片的功能相似,只是代码比较简单,功能没有SD的完善与强大,支持缺省添加图片,支持本地缓存. 异步加载图片的核心代码如下:  func setZYHWebImage(url:NSString?, defaultImage:NSString?, isCache:Bool){         var ZYHImage:UIImage?         if url == nil {             return   

Android异步加载全解析之Bitmap

Android异步加载全解析之Bitmap 在这篇文章中,我们分析了Android在对大图处理时的一些策略--Android异步加载全解析之大图处理  戳我戳我 那么在这篇中,我们来对图像--Bitmap进行一个更加细致的分析,掌握Bitmap的点点滴滴. 引入 Bitmap这玩意儿号称Android App头号杀手,特别是3.0之前的版本,简直就是皇帝般的存在,碰不得.摔不得.虽然后面的版本Android对Bitmap的管理也进行了一系列的优化,但是它依然是非常难处理的一个东西.在Androi

Android异步加载全解析之开篇瞎扯淡

Android异步加载 概述 Android异步加载在Android中使用的非常广泛,除了是因为避免在主线程中做网络操作,更是为了避免在显示时由于时间太长而造成ANR,增加显示的流畅性,特别是像ListView.GridView这样的控件,如果getView的时间太长,就会造成非常严重的卡顿,非常影响性能. 本系列将展示在Android中如何进行异步加载操作,并使用ListView来作为演示的对象. 如何下载图像 下载自然是需要使用网络,使用网络就不能在主线程,在主线程就会爆炸.所以我们必须要在