Android圖片加載框架Picasso

參考鏈接

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章