在Android的应用中实现网络图片异步加载的方法

前言
其实很幸运,入职一周之后就能跟着两个师兄做android开发,师兄都是大神,身为小白的我只能多多学习,多多努力。最近一段时间都忙的没机会总结,今天刚完成了android客户端图片异步加载的类,这里记录一下(ps:其实我这里都是参考网上开源实现)

原理
在ListView或者GridView中加载图片的原理基本都是一样的:

先从内存缓存中获取,取到则返回,取不到进行下一步
    从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行进行下一步
    从网络上下载图片,并更新内存缓存和文件缓存

流程图如下:

同时,要注意线程的数量。一般在listview中加载图片,大家都是开启新的线程去加载,但是当快速滑动时,很容易造成OOM,因此需要控制线程数量。我们可以通过线程池控制线程的数量,具体线程池的大小还需要根据处理器的情况和业务情况自行判断

建立线程池的方法如下:

ExecutorService executorService = Executors.newFixedThreadPool(5); // 5是可变的

文件缓存类

 import java.io.File; 

  import android.content.Context; 

  public class FileCache {
    private static final String DIR_NAME = "your_dir";
    private File cacheDir; 

    public FileCache(Context context) {
      // Find the directory to save cached images
      if (android.os.Environment.getExternalStorageState().equals(
          android.os.Environment.MEDIA_MOUNTED)) {
        cacheDir = new File(
            android.os.Environment.getExternalStorageDirectory(),
            DIR_NAME);
      } else {
        cacheDir = context.getCacheDir();
      } 

      if (!cacheDir.exists()) {
        cacheDir.mkdirs();
      }
    } 

    public File getFile(String url) {
      // Identify images by url's hash code
      String filename = String.valueOf(url.hashCode()); 

      File f = new File(cacheDir, filename); 

      return f;
    } 

    public void clear() {
      File[] files = cacheDir.listFiles();
      if (files == null) {
        return;
      } else {
        for (File f : files) {
          f.delete();
        }
      }
    }
  }

内存缓存类
这里使用了软引用,Map<String, SoftReference<Bitmap>> cache,可以google一下软引用的机制,简单的说:实现了map,同时当内存紧张时可以被回收,不会造成内存泄露

 import java.lang.ref.SoftReference;
  import java.util.Collections;
  import java.util.LinkedHashMap;
  import java.util.Map; 

  import android.graphics.Bitmap; 

  public class MemoryCache {
    private Map<String, SoftReference<Bitmap>> cache = Collections
        .synchronizedMap(new LinkedHashMap<String, SoftReference<Bitmap>>(
            10, 1.5f, true)); 

    public Bitmap get(String id) {
      if (!cache.containsKey(id)) {
        return null;
      } 

      SoftReference<Bitmap> ref = cache.get(id); 

      return ref.get();
    } 

    public void put(String id, Bitmap bitmap) {
      cache.put(id, new SoftReference<Bitmap>(bitmap));
    } 

    public void clear() {
      cache.clear();
    }
  }

图片加载类

  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.util.Collections;
  import java.util.Map;
  import java.util.WeakHashMap;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors; 

  import android.content.Context;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import android.os.Handler;
  import android.widget.ImageView; 

  public class ImageLoader {
    /**
     * Network time out
     */
    private static final int TIME_OUT = 30000;
    /**
     * Default picture resource
     */
    private static final int DEFAULT_BG = R.drawable.plate_list_head_bg; 

    /**
     * Thread pool number
     */
    private static final int THREAD_NUM = 5; 

    /**
     * Memory image cache
     */
    MemoryCache memoryCache = new MemoryCache(); 

    /**
     * File image cache
     */
    FileCache fileCache; 

    /**
     * Judge image view if it is reuse
     */
    private Map<ImageView, String> imageViews = Collections
        .synchronizedMap(new WeakHashMap<ImageView, String>()); 

    /**
     * Thread pool
     */
    ExecutorService executorService; 

    /**
     * Handler to display images in UI thread
     */
    Handler handler = new Handler(); 

    public ImageLoader(Context context) {
      fileCache = new FileCache(context);
      executorService = Executors.newFixedThreadPool(THREAD_NUM);
    } 

    public void disPlayImage(String url, ImageView imageView) {
      imageViews.put(imageView, url);
      Bitmap bitmap = memoryCache.get(url);
      if (bitmap != null) {
        // Display image from Memory cache
        imageView.setImageBitmap(bitmap);
      } else {
        // Display image from File cache or Network
        queuePhoto(url, imageView);
      }
    } 

    private void queuePhoto(String url, ImageView imageView) {
      PhotoToLoad photoToLoad = new PhotoToLoad(url, imageView);
      executorService.submit(new PhotosLoader(photoToLoad));
    } 

    private Bitmap getBitmap(String url) {
      File f = fileCache.getFile(url); 

      // From File cache
      Bitmap bmp = decodeFile(f);
      if (bmp != null) {
        return bmp;
      } 

      // From Network
      try {
        Bitmap bitmap = null;
        URL imageUrl = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) imageUrl
            .openConnection();
        conn.setConnectTimeout(TIME_OUT);
        conn.setReadTimeout(TIME_OUT);
        conn.setInstanceFollowRedirects(true);
        InputStream is = conn.getInputStream();
        OutputStream os = new FileOutputStream(f);
        copyStream(is, os);
        os.close();
        conn.disconnect();
        bitmap = decodeFile(f);
        return bitmap;
      } catch (Throwable ex) {
        if (ex instanceof OutOfMemoryError) {
          clearCache();
        }
        return null;
      } 

    } 

    private void copyStream(InputStream is, OutputStream os) {
      int buffer_size = 1024; 

      try {
        byte[] bytes = new byte[buffer_size];
        while (true) {
          int count = is.read(bytes, 0, buffer_size);
          if (count == -1) {
            break;
          }
          os.write(bytes, 0, count);
        } 

      } catch (Exception e) { 

      }
    } 

    private Bitmap decodeFile(File f) {
      try {
        // TODO:Compress image size
        FileInputStream fileInputStream = new FileInputStream(f);
        Bitmap bitmap = BitmapFactory.decodeStream(fileInputStream);
        return bitmap; 

      } catch (FileNotFoundException e) {
        return null;
      }
    } 

    private void clearCache() {
      memoryCache.clear();
      fileCache.clear();
    } 

    /**
     * Task for the queue
     *
     * @author zhengyi.wzy
     *
     */
    private class PhotoToLoad {
      public String url;
      public ImageView imageView; 

      public PhotoToLoad(String url, ImageView imageView) {
        this.url = url;
        this.imageView = imageView;
      }
    } 

    /**
     * Asynchronous to load picture
     *
     * @author zhengyi.wzy
     *
     */
    class PhotosLoader implements Runnable {
      PhotoToLoad photoToLoad; 

      public PhotosLoader(PhotoToLoad photoToLoad) {
        this.photoToLoad = photoToLoad;
      } 

      private boolean imageViewReused(PhotoToLoad photoToLoad) {
        String tag = imageViews.get(photoToLoad.imageView);
        if (tag == null || !tag.equals(photoToLoad.url)) {
          return true;
        } 

        return false;
      } 

      @Override
      public void run() {
        // Abort current thread if Image View reused
        if (imageViewReused(photoToLoad)) {
          return;
        } 

        Bitmap bitmap = getBitmap(photoToLoad.url); 

        // Update Memory
        memoryCache.put(photoToLoad.url, bitmap); 

        if (imageViewReused(photoToLoad)) {
          return;
        } 

        // Don't change UI in children thread
        BitmapDisplayer bd = new BitmapDisplayer(bitmap, photoToLoad);
        handler.post(bd);
      } 

      class BitmapDisplayer implements Runnable {
        Bitmap bitmap;
        PhotoToLoad photoToLoad; 

        public BitmapDisplayer(Bitmap bitmap, PhotoToLoad photoToLoad) {
          this.bitmap = bitmap;
          this.photoToLoad = photoToLoad;
        } 

        @Override
        public void run() {
          if (imageViewReused(photoToLoad)) {
            return;
          } 

          if (bitmap != null) {
            photoToLoad.imageView.setImageBitmap(bitmap);
          } else {
            photoToLoad.imageView.setImageResource(DEFAULT_BG);
          }
        } 

      }
    }
  }

调用方法

  ImageLoader imageLoader = new ImageLoader(context);
  imageLoader.disPlayImage(imageUrl, imageView);

(0)

相关推荐

  • android异步加载图片并缓存到本地实现方法

    在android项目中访问网络图片是非常普遍性的事情,如果我们每次请求都要访问网络来获取图片,会非常耗费流量,而且图片占用内存空间也比较大,图片过多且不释放的话很容易造成内存溢出.针对上面遇到的两个问题,首先耗费流量我们可以将图片第一次加载上面缓存到本地,以后如果本地有就直接从本地加载.图片过多造成内存溢出,这个是最不容易解决的,要想一些好的缓存策略,比如大图片使用LRU缓存策略或懒加载缓存策略.今天首先介绍一下本地缓存图片. 首先看一下异步加载缓存本地代码: 复制代码 代码如下: public

  • Android 异步加载图片的实例代码

    异步加载图片的主要流程是进行判断缓存中是否存在图片,如果存在则直接返回,如果不存在则进行下载并进行缓存. 以下是建立一个异步下载类: 复制代码 代码如下: /** * User: Tom * Date: 13-5-13 * Time: 下午8:07 */public class AsnycImageLoader { //定义一个HashMap进行存放缓存的Image key为String Value为一个弱引用的一个资源文件    // 图片 为了方便JAVA的回收    private Map

  • Android实现图片缓存与异步加载

    ImageManager2这个类具有异步从网络下载图片,从sd读取本地图片,内存缓存,硬盘缓存,图片使用动画渐现等功能,已经将其应用在包含大量图片的应用中一年多,没有出现oom. Android程序常常会内存溢出,网上也有很多解决方案,如软引用,手动调用recycle等等.但经过我们实践发现这些方案,都没能起到很好的效果,我们的应用依然会出现很多oom,尤其我们的应用包含大量的图片.android3.0之后软引用基本已经失效,因为虚拟机只要碰到软引用就回收,所以带不来任何性能的提升. 我这里的解

  • Android实现ListView异步加载图片的方法

    本文实例讲述了Android实现ListView异步加载图片的方法.分享给大家供大家参考.具体如下: ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,不用让用户等待下去,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReferen

  • Android实现异步加载图片

    麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的. 今天在做项目的时候,有一个实现异步加载图片的功能,虽然比较简单但还是记录一下吧.因为麦洛之前实现异步加载图片都是使用了AsynTask这个API,继续这个类,实现起来非常简单也很方便.在doInBackground()方法里实现下载逻辑.具体实现如下 实现逻辑是:先从内存中读取,如果内存中有这张图片,则直接使用;如果内存没有再到sdcard上读取,如果有则显示;如

  • Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而Ima

  • Android中使用二级缓存、异步加载批量加载图片完整案例

    一.问题描述 Android应用中经常涉及从网络中加载大量图片,为提升加载速度和效率,减少网络流量都会采用二级缓存和异步加载机制,所谓二级缓存就是通过先从内存中获取.再从文件中获取,最后才会访问网络.内存缓存(一级)本质上是Map集合以key-value对的方式存储图片的url和Bitmap信息,由于内存缓存会造成堆内存泄露, 管理相对复杂一些,可采用第三方组件,对于有经验的可自己编写组件,而文件缓存比较简单通常自己封装一下即可.下面就通过案例看如何实现网络图片加载的优化. 二.案例介绍 案例新

  • Android实现Listview异步加载网络图片并动态更新的方法

    本文实例讲述了Android实现Listview异步加载网络图片并动态更新的方法.分享给大家供大家参考,具体如下: 应用实例:解析后台返回的数据,把每条都显示在ListView中,包括活动图片.店名.活动详情.地址.电话和距离等. 在布局文件中ListView的定义: <ListView android:id="@id/maplistview" android:background="@drawable/bg" android:layout_width=&qu

  • Android App中实现图片异步加载的实例分享

    一.概述 一般大量图片的加载,比如GridView实现手机的相册功能,一般会用到LruCache,线程池,任务队列等:那么异步消息处理可以用哪呢? 1.用于UI线程当Bitmap加载完成后更新ImageView 2.在图片加载类初始化时,我们会在一个子线程中维护一个Loop实例,当然子线程中也就有了MessageQueue,Looper会一直在那loop停着等待消息的到达,当有消息到达时,从任务队列按照队列调度的方式(FIFO,LIFO等),取出一个任务放入线程池中进行处理. 简易的一个流程:当

  • Android 异步加载图片分析总结

    研究了android从网络上异步加载图像,现总结如下: (1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法. 在主线程中new 一个Handler对象,加载图像方法如下所示 复制代码 代码如下: private void loadImage(final String url, final int id) { handler.post(new Runnable() { public void run() { Drawable

随机推荐