Android实现图片异步加载并缓存到本地

在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片。

软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地有没有,如果没有再从网络读取。

下面就分享一下异步加载网络图片的方法吧。

FileCache.java

import java.io.File;
import android.content.Context; 

public class FileCache { 

  private File cacheDir; 

  public FileCache(Context context) {
    // 找一个用来缓存图片的路径
    if (android.os.Environment.getExternalStorageState().equals(
        android.os.Environment.MEDIA_MOUNTED))
      cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),
          "文件夹名称");
    else
      cacheDir = context.getCacheDir();
    if (!cacheDir.exists())
      cacheDir.mkdirs();
  } 

  public File getFile(String url) {
    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;
    for (File f : files)
      f.delete();
  } 

}

HttpUtil.java

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map; 

/**
* Http 请求工具类
*
* @author Scorpio.Liu
*
*/
public class HttpUtil { 

  /**
  * 获取响应字符串
  *
  * @param path
  *      路径
  * @param parameters
  *      参数
  * @return 响应字符串
  */
  public static String getResponseStr(String path, Map<String, String> parameters) {
    StringBuffer buffer = new StringBuffer();
    URL url;
    try {
      if (parameters != null && !parameters.isEmpty()) {
        for (Map.Entry<String, String> entry : parameters.entrySet()) {
          // 完成转码操作
          buffer.append(entry.getKey()).append("=")
              .append(URLEncoder.encode(entry.getValue(), "UTF-8")).append("&");
        }
        buffer.deleteCharAt(buffer.length() - 1);
      }
      url = new URL(path);
      HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
      urlConnection.setConnectTimeout(3000);
      urlConnection.setRequestMethod("POST");
      urlConnection.setDoInput(true);// 表示从服务器获取数据
      urlConnection.setDoOutput(true);// 表示向服务器写数据
      // 获得上传信息的字节大小以及长度
      byte[] mydata = buffer.toString().getBytes();
      // 表示设置请求体的类型是文本类型
      urlConnection.setRequestProperty("Content-Type",
          "application/x-www-form-urlencoded");
      urlConnection.setRequestProperty("Content-Length", String.valueOf(mydata.length));
      // 获得输出流,向服务器输出数据
      OutputStream outputStream = urlConnection.getOutputStream();
      outputStream.write(mydata, 0, mydata.length);
      outputStream.close();
      int responseCode = urlConnection.getResponseCode();
      if (responseCode == 200) {
        return changeInputStream(urlConnection.getInputStream());
      }
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    } catch (MalformedURLException e) {
      e.printStackTrace();
    } catch (ProtocolException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  } 

  private static String changeInputStream(InputStream inputStream) {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    byte[] data = new byte[1024];
    int len = 0;
    String result = "";
    if (inputStream != null) {
      try {
        while ((len = inputStream.read(data)) != -1) {
          outputStream.write(data, 0, len);
        }
        result = new String(outputStream.toByteArray(), "UTF-8");
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return result;
  } 

  public static InputStream getInputStream(String path) {
    URL url;
    try {
      url = new URL(path);
      HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
      urlConnection.setConnectTimeout(3000);
      urlConnection.setRequestMethod("GET");
      urlConnection.setDoInput(true);// 表示从服务器获取数据
      urlConnection.connect();
      if (urlConnection.getResponseCode() == 200)
        return urlConnection.getInputStream();
    } catch (MalformedURLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  } 

  public static byte[] readStream(InputStream inStream) throws Exception {
    ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = -1;
    while ((len = inStream.read(buffer)) != -1) {
      outSteam.write(buffer, 0, len); 

    }
    outSteam.close();
    inStream.close();
    return outSteam.toByteArray();
  } 

  public static void CopyStream(String url, File f) {
    FileOutputStream fileOutputStream = null;
    InputStream inputStream = null;
    try {
      inputStream = getInputStream(url);
      byte[] data = new byte[1024];
      int len = 0;
      fileOutputStream = new FileOutputStream(f);
      while ((len = inputStream.read(data)) != -1) {
        fileOutputStream.write(data, 0, len);
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if (fileOutputStream != null) {
        try {
          fileOutputStream.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  } 

} 

MemoryCache.java

import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import android.graphics.Bitmap; 

public class MemoryCache {
  private Map<String, SoftReference<Bitmap>> cache = Collections
      .synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());// 软引用 

  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();
  }
}

ImageLoader.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.widget.ImageView; 

public class ImageLoader { 

  private MemoryCache memoryCache = new MemoryCache();
  private FileCache fileCache;
  private Map<ImageView, String> imageViews = Collections
      .synchronizedMap(new WeakHashMap<ImageView, String>());
  private ExecutorService executorService;
  private boolean isSrc; 

  /**
  * @param context
  *      上下文对象
  * @param flag
  *      true为source资源,false为background资源
  */
  public ImageLoader(Context context, boolean flag) {
    fileCache = new FileCache(context);
    executorService = Executors.newFixedThreadPool(5);
    isSrc = flag;
  } 

  final int stub_id = R.drawable.ic_launcher; 

  public void DisplayImage(String url, ImageView imageView) {
    String u1 = url.substring(0, url.lastIndexOf("/") + 1);
    String u2 = url.substring(url.lastIndexOf("/") + 1);
    try {
      u2 = URLEncoder.encode(u2, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
    }
    url = u1 + u2;
    imageViews.put(imageView, url);
    Bitmap bitmap = memoryCache.get(url);
    if (bitmap != null) {
      if (isSrc)
        imageView.setImageBitmap(bitmap);
      else
        imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));
    } else {
      queuePhoto(url, imageView);
      if (isSrc)
        imageView.setImageResource(stub_id);
      else
        imageView.setBackgroundResource(stub_id);
    }
  } 

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

  private Bitmap getBitmap(String url) {
    try {
      File f = fileCache.getFile(url);
      // 从sd卡
      Bitmap b = onDecodeFile(f);
      if (b != null)
        return b;
      // 从网络
      Bitmap bitmap = null;
      System.out.println("ImageLoader-->download");
      HttpUtil.CopyStream(url, f);
      bitmap = onDecodeFile(f); 

      return bitmap;
    } catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  } 

  public Bitmap onDecodeFile(File f) {
    try {
      return BitmapFactory.decodeStream(new FileInputStream(f));
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  } 

  /**
  * 解码图像用来减少内存消耗
  *
  * @param f
  * @return
  */
  public Bitmap decodeFile(File f) {
    try {
      // 解码图像大小
      BitmapFactory.Options o = new BitmapFactory.Options();
      o.inJustDecodeBounds = true;
      BitmapFactory.decodeStream(new FileInputStream(f), null, o);
      // 找到正确的刻度值,它应该是2的幂。
      final int REQUIRED_SIZE = 70;
      int width_tmp = o.outWidth, height_tmp = o.outHeight;
      int scale = 1;
      while (true) {
        if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
          break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
      }
      BitmapFactory.Options o2 = new BitmapFactory.Options();
      o2.inSampleSize = scale;
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {
    }
    return null;
  } 

  /**
  * 任务队列
  *
  * @author Scorpio.Liu
  *
  */
  private class PhotoToLoad {
    public String url;
    public ImageView imageView; 

    public PhotoToLoad(String u, ImageView i) {
      url = u;
      imageView = i;
    }
  } 

  class PhotosLoader implements Runnable {
    PhotoToLoad photoToLoad; 

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

    @Override
    public void run() {
      if (imageViewReused(photoToLoad))
        return;
      Bitmap bmp = getBitmap(photoToLoad.url);
      memoryCache.put(photoToLoad.url, bmp);
      if (imageViewReused(photoToLoad))
        return;
      BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
      Activity a = (Activity) photoToLoad.imageView.getContext();
      a.runOnUiThread(bd);
    }
  } 

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

  /**
  * 显示位图在UI线程
  *
  * @author Scorpio.Liu
  *
  */
  class BitmapDisplayer implements Runnable {
    Bitmap bitmap;
    PhotoToLoad photoToLoad; 

    public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
      bitmap = b;
      photoToLoad = p;
    } 

    public void run() {
      if (imageViewReused(photoToLoad))
        return;
      if (bitmap != null) {
        if (isSrc)
          photoToLoad.imageView.setImageBitmap(bitmap);
        else
          photoToLoad.imageView.setBackgroundDrawable(new BitmapDrawable(bitmap));
      } else {
        if (isSrc)
          photoToLoad.imageView.setImageResource(stub_id);
        else
          photoToLoad.imageView.setBackgroundResource(stub_id);
      }
    }
  } 

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

}

使用的时候用ImageLoader这个类就ok了,很方便~

希望本文所述对大家学习Android软件编程有所帮助。

(0)

相关推荐

  • Android异步下载图片并且缓存图片到本地DEMO详解

    在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML资源,其中包括图片,我们要做的解析XML里面的数据,并且把图片缓存到本地一个cache目录里面,并且用一个自定义的Adapter去填充到LIstView,demo运行效果见下图: 通过这个demo,要学会有一下几点 1.怎么解析一个XML 2.demo中用到的缓存图片到本地一个临时目录的思想是怎样的? 3.AsyncTask类的使用,因为要去异

  • Android实现图片异步加载及本地缓存

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

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

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

  • Android远程获取图片并本地缓存

    对于客户端--服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量,对应用来说,如果处理不好这个问题,那会让用户很崩溃,不知不觉手机流量就用完了,等用户发现是你的应用消耗掉了他手机流量的话,那么可想而知你的应用将面临什么样的命运. 另外一个问题就是加载速度,如果应用中图片加载速度很慢的话,那么用户同样会等到崩溃. 那么如何处理好图片资源的获取和管理呢? *异步下载 *本地缓存 1.异步下载: 大家都知道,在android应用中UI线程5秒没响应的话就会抛出无响应异

  • Android图片三级缓存策略(网络、本地、内存缓存)

    一.简介 现在的Android应用程序中,不可避免的都会使用到图片,如果每次加载图片的时候都要从网络重新拉取,这样不但很耗费用户的流量,而且图片加载的也会很慢,用户体验很不好.所以一个应用的图片缓存策略是很重要的.通常情况下,Android应用程序中图片的缓存策略采用"内存-本地-网络"三级缓存策略,首先应用程序访问网络拉取图片,分别将加载的图片保存在本地SD卡中和内存中,当程序再一次需要加载图片的时候,先判断内存中是否有缓存,有则直接从内存中拉取,否则查看本地SD卡中是否有缓存,SD

  • Android使用缓存机制实现文件下载及异步请求图片加三级缓存

    首先给大家介绍Android使用缓存机制实现文件下载 在下载文件或者在线浏览文件时,或者为了保证文件下载的正确性,需要使用缓存机制,常使用SoftReference来实现. SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收.也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用.另外

  • Android实现图片异步加载并缓存到本地

    在android应用开发的时候,加载网络图片是一个非常重要的部分,很多图片不可能放在本地,所以就必须要从服务器或者网络读取图片. 软引用是一个现在非常流行的方法,用户体验比较好,不用每次都需要从网络下载图片,如果下载后就存到本地,下次读取时首先查看本地有没有,如果没有再从网络读取. 下面就分享一下异步加载网络图片的方法吧. FileCache.java import java.io.File; import android.content.Context; public class FileCa

  • Android图片异步加载框架Android-Universal-Image-Loader

    Android-Universal-Image-Loader是一个图片异步加载,缓存和显示的框架.这个框架已经被很多开发者所使用,是最常用的几个Android开源项目之一,主流的应用,随便反编译几个,都可以见到它的身影.淘宝,天猫,Facebook,京东商城等都用到了这个项目. 该项目的Github地址链接 运行流程: 每一个图片的加载和显示任务都运行在独立的线程中,除非这个图片缓存在内存中,这种情况下图片会立即显示.如果需要的图片缓存在本地,它会开启一个独立的线程队列.如果在缓存中没有正确的图

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

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

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

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

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

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

  • Android实现ListView异步加载的方法(改进版)

    本文实例讲述了Android实现ListView异步加载的方法.分享给大家供大家参考,具体如下: @Override public View getView(int position, View convertView, ViewGroup parent) { ---- ViewHolder VH = null; ---- VH.mImageView.setTag(position); VH.mThumb.setImageDrawable(imageLoader.loadDrawable(pos

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

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

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

    前言 其实很幸运,入职一周之后就能跟着两个师兄做android开发,师兄都是大神,身为小白的我只能多多学习,多多努力.最近一段时间都忙的没机会总结,今天刚完成了android客户端图片异步加载的类,这里记录一下(ps:其实我这里都是参考网上开源实现) 原理 在ListView或者GridView中加载图片的原理基本都是一样的: 先从内存缓存中获取,取到则返回,取不到进行下一步     从文件缓存中获取,取到则返回并更新到内存缓存,取不到则进行进行下一步     从网络上下载图片,并更新内存缓存和

随机推荐