参考链接

http://bbs.itcast.cn/thread-87019-1-1.html

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0731/1639.html

1 Picasso介绍

picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能。github地址是https://github.com/square/picasso

Picasso不仅实现了图片异步加载的功能,还解决了android中加载图片时需要解决的一些常见问题:

  • 1.在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题。

  • 2.使用复杂的图片压缩转换来尽可能的减少内存消耗

  • 3.自带内存和硬盘二级缓存功能

Android系统作为图片资源加载的主角,它是通过图像的像素点来把图像加载到内存中的;现在一张500W的摄像头拍出的照片(2592x1936),加载到内存中需要大约19M的内存;如果你加入了信号强度不一的网络中进行了复杂的网络请求,并进行图片的缓存与其他处理,你会耗费大量的时间与精力来处理这些问题,但如果用了Picasso, 这些问题都一消而散;

2 Picasso的使用

(1)使用前

在Android studio中使用Picasso,在Gradle中添加

compile 'com.squareup.picasso:picasso:2.5.2'

如果使用ProGuard打包的话,需要将以下代码添加到混淆规则文件中::

-dontwarn com.squareup.okhttp.**

(2)从网络加载一张图片

Picasso使用简单易用的接口,并有一个实现类Picasso,一个完整的功能请求至少需要三个参数:

  • with(Context context) - Context上下文在很多Android Api中都是必须的

  • load(String imageUrl) - 图片网络加载地址

  • into(ImageView targetImageView) - 想进行图片展示的ImageView

ImageView targetImageView = (ImageView) findViewById(R.id.imageView);
String internetUrl = "http://www.jycoder.com/json/Image/1.jpg";

Picasso
    .with(context)
    .load(internetUrl)
    .into(targetImageView);

(3)从Android Resources中加载

代码也是三行,只需要将网络资源地址更改为一个int值地址即可,上代码:

ImageView targetImageView = (ImageView) findViewById(R.id.imageView);
int resourceId = R.mipmap.ic_launcher;

Picasso
    .with(context)
    .load(resourceId)
    .into(targetImageView);

(4)从本地File文件中加载

如果你让用户选择本地的一张图片进行展示的话,就需要用到这个加载方式了,当然,也是So Easy,只需要将地址更换为一个File即可,上代码:

ImageView targetImageView = (ImageView) findViewById(R.id.imageView);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Running.jpg");

Picasso
    .with(context)
    .load(file)
    .into(targetImageView);

3 LruCache分析

Lrucacha,存储的结构采用了LinkedHashMap,这种map内部实现了lru算法(Least Recently Used 近期最少使用算法)。

this.map = new LinkedHashMap<String, Bitmap>(0, 0.75f, true);

其中第三个参数的意思是:
-true : 按照访问的循序排序
-false: 按照插入的顺序排序
Lru算法是最近最少使用,需要按照访问的顺序来排序,所说义设为true

主要是get和set方法:
get()方法

@Override public Bitmap get(String key) {
    if (key == null) {
      throw new NullPointerException("key == null");
    }

    Bitmap mapValue;
    synchronized (this) {
      mapValue = map.get(key);
      if (mapValue != null) {
        hitCount++;
        return mapValue;
      }
      missCount++;
    }

    return null;
  }

set方法

@Override public void set(String key, Bitmap bitmap) {
    if (key == null || bitmap == null) {
      throw new NullPointerException("key == null || bitmap == null");
    }

    Bitmap previous;
    synchronized (this) {
      putCount++;
      size += Utils.getBitmapBytes(bitmap);
      previous = map.put(key, bitmap);
      if (previous != null) {
        size -= Utils.getBitmapBytes(previous);
      }
    }

    trimToSize(maxSize);
  }

因为可能会涉及多线程,所以在存取的时候都会加锁。而且每次set操作后都会判断当前缓存区是否已满,如果满了就清掉最少使用的图形。代码如下:

private void trimToSize(int maxSize) {
        while (true) {
            String key;
            Bitmap value;
            synchronized (this) {
                if (size < 0 || (map.isEmpty() && size != 0)) {
                    throw new IllegalStateException(getClass().getName()
                            + ".sizeOf() is reporting inconsistent results!");
                }

                if (size <= maxSize || map.isEmpty()) {
                    break;
                }

                Map.Entry<String, Bitmap> toEvict = map.entrySet().iterator()
                        .next();
                key = toEvict.getKey();
                value = toEvict.getValue();
                map.remove(key);
                size -= Utils.getBitmapBytes(value);
                evictionCount++;
            }
        }
}

4 遇到的问题及解决方案

我在项目中,使用内部类Target的对象作为into()的参数时,发现第一次总是无法获取头像,即不回调onBitmapLoaded()方法而是回调了onPrepareLoad()方法。在stackoverflow中得知Picasso对Target是弱引用,当发生内存回收时Target对象被回收旧无法完成加载图像。解决的方法是将Target对象设置为View的Tag,再通过view的getTag()方法来得到Target的对象。

http://stackoverflow.com/questions/24180805/onbitmaploaded-of-target-object-not-called-on-first-load
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐