欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-05 12:16:06
前言 其实很幸运,入职一周之后就能跟着两个师兄做android开发,师兄都是大神,身为小白的我只能多多学习,多多努力。最近一段时间都忙的没机会总结,今天刚完成了andro...

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


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

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


流程图如下:

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

同时,要注意线程的数量。一般在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);