栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

分享一个轻量级图片加载类 ImageLoader

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

分享一个轻量级图片加载类 ImageLoader

ImageLoader 这类的 图片加载网络上一大推,像比较出名的有nostra13 的-Image-Loader图片加载,xUtil的图片加载,还有 Facebook 的 Fresco 。很多,但本着求学的态度,最近在做项目时有图片加载这个需求就自己写了个轻量级的 (本地)图片缓存加载 功能,分享给各位。

里面涉及了 LruCache ,ExecutorService,处理大图的 BitmapFactory 原理,view.setTag() .

好了,不多说,先一步一步来:
首先看一下我封装的类怎么使用:

    // 本地照片绝对路径
    String imageUrl = (String) t;
    // 得到 ImageView 
    ImageView grid_item = holder.getView(R.id.grid_item);
    // 设置 tag ,标记用的,反正图片显示错位
    grid_item.setTag(imageUrl);
    
     
 
    new ImageLoader().displayBmp(mContext,grid_item, imageUrl, R.drawable.img_bg,this);
 

是不是很简单。

接下来具体分析 ImageLoader 这个类:

都知道手机的内存有限,不可能将所有的图片都加进内存,所以android 提供了一个 LruCache 方法,用到的 算法 是 :近期最少使用算法 ,及在图片不断的加进缓存,最少使用的图片也在不断的移除缓存 ,从而避免的内存不够的问题。

LruCache 的初始化代码如下:

  public ImageLoader() {

    // 取应用内存的 8/1 作为 图片缓存用
    int cacheSize = maxMemory / 8;
    // 得到 LruCache
    mLruCache = new LruCache(cacheSize) {
      @Override
      protected int sizeOf(String key, Bitmap bitmap) {
 return bitmap.getByteCount();
      }
    };

  }

  
  public void putBitmapToLruCache(String key, Bitmap bitmap) {
    if (getBitmapFromLruCache(key) == null && mLruCache != null) {
      mLruCache.put(key, bitmap);
    }
  }
  
  public Bitmap getBitmapFromLruCache(String key) {
    return mLruCache.get(key);
  }

LruCache 就像 HashMap 一样 利用put 和 get 得到缓存的东西。

接着看 图片的 具体加载,先把代码贴出来:

  
  public void displayBmp(final Context context, final ImageView imageView, final String sourcePath, final int r_Id,
      final ImageCallback callback) {

    final String path;

    if (!TextUtils.isEmpty(sourcePath)) {
      path = sourcePath;

    } else {
      return;
    }
    // 先 试着 从 缓存 得到 图片 , path 作为 图片的 key
    Bitmap bmp = mLruCache.get(path);

    if (bmp != null) {
      if (callback != null) {
 // 回调 图片 显示
 callback.imageLoad(imageView, bmp, sourcePath);
      }
      // imageView.setImageBitmap(bmp);
      return;
    }
    // 如果 bmp == null ,给 imageView 显示默认图片
    imageView.setImageResource(r_Id);
    // 启动 线程池
    threadPoolUtils.getExecutorService().execute(new Runnable() {
      Bitmap bitmap = null;

      @Override
      public void run() {
 // TODO Auto-generated method stub

 try {
   // 加载 图片 地址 对应 的 缩略图
   bitmap = revitionImageSize(imageView, sourcePath);
 } catch (Exception e) {

 }
 if (bitmap == null) {
   try {
     // 如果 缩略图 没加载成功 显示 默认 设置的图片
     bitmap = BitmapFactory.decodeResource(context.getResources(), r_Id);
   } catch (Exception e) {
   }
 }
 if (path != null && bitmap != null) {
   // 将 缩略图 放进 缓存 , path 作为 key
   putBitmapToLruCache(path, bitmap);
 }

 if (callback != null) {
   handler.post(new Runnable() {
     @Override
     public void run() {
// 回调 图片 显示
callback.imageLoad(imageView, bitmap, sourcePath);

     }
   });
 }

      }
    });

  }

代码不是狠多,主要就是 先从缓存加载图片,当加载图片为空时,再从手机的图片地址加载图片

bitmap = revitionImageSize(imageView, sourcePath);

加载缓存图片就不多说了,看的也明白, mLruCache.get(key);就这么简单

具体分析 revitionImageSize() 这个方法吧:

  public Bitmap revitionImageSize(ImageView imageView, String path) throws IOException {

    // 得到 布局 ImageView 的 宽高
    int img_width = imageView.getWidth();
    int img_height = imageView.getHeight();
 
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(new File(path)));
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeStream(in, null, options);
    in.close();

    int height = options.outHeight;
    int width = options.outWidth;

    Bitmap bitmap = null;
 
    int inSampleSize = 1;

    // 计算出实际宽高和目标宽高的比率
    final int heightRatio = Math.round((float) height / (float) img_height);
    final int widthRatio = Math.round((float) width / (float) img_width);
    // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
    // 一定都会大于等于目标的宽和高。
    inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    // 调用上面定义的方法计算inSampleSize值
    options.inSampleSize = inSampleSize;

    options.inJustDecodeBounds = false;
    in = new BufferedInputStream(new FileInputStream(new File(path)));
    bitmap = BitmapFactory.decodeStream(in, null, options);

    in.close();
    return bitmap;
  }

代码我也写了注释了 ,一般在加载图片时都有对图片一定的压缩处理避免OOM,所以上面的处理方法也是挺常见的,对要显示 图片 根据 imageview 控件大小进行一定的压缩。

如果对 图片压缩处理不是很理解的朋友这么我简单解释一下:

首先加载完图片:

BufferedInputStream in = new BufferedInputStream(new FileInputStream(new File(path)));

然后:

options.inJustDecodeBounds = true;

再接着:

int height = options.outHeight;
int width = options.outWidth;

这时候注意 程序并没有把图片真正的加载进来,options.inJustDecodeBounds = true;

这句在起作用,但图片的宽和高 的信息我们却得到了,就可以处理压缩图片了!

压缩完图片再:

options.inJustDecodeBounds = false;

重新得到压缩后的图片:

bitmap = BitmapFactory.decodeStream(in, null, options);

解释完毕。

仔细看代码的同学会发现 displayBmp() 方法里面有个 回调参数:

回调接口如下:

  
  public interface ImageCallback {
    public void imageLoad(ImageView imageView, Bitmap bitmap, Object... params);
  }

具体实现是在显示图片的地方回调的:

   
  @Override
  public void imageLoad(ImageView imageView, Bitmap bitmap, Object... params) {
    if (imageView != null && bitmap != null) {
      String url = (String) params[0];

      // 判断 这里的 url 是否 对应 imageView.getTag()
      // 如果 将这句 判断 去掉 那么 就会出现 经常出现的 图片 显示 错位 问题 !!!!
      if (url != null && url.equals((String) imageView.getTag())) {

 ((ImageView) imageView).setImageBitmap(bitmap);
      }
    }
  }

代码注释的地方也写了,不太理解的同学可以私信交流,另外附上我 github github连接上的源码,可以下载下了运行方便好理解:

为了你方便使用,在你的项目中添加如下依赖即可:

dependencies {
      compile 'com.zts:imageloader:1.1.1'

  }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/161787.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号