圖片加載框架-Picasso最詳細的使用指南

寫在前面

Android 中有幾個比較有名的圖片加載框架,Universal ImageLoader、Picasso、Glide和Fresco。它們各有優點,以前一直用的是ImageLoader 做項目中的圖片加載,由于作者宣布ImageLoader 不會在更新了,因此新的項目打算換一個圖片加載框架-Picasso, Picasso 是Square 公司開源的Android 端的圖片加載和緩存框架。Square 真是一家良心公司啊,為我們Android開發者貢獻了很多優秀的開源項目有木有!像什么Rerefoit 、OkHttp、LeakCanary、Picasso等等都是非常火的開源項目。扯遠了,回到正題,除了使用簡單方便,Picasso還能自動幫我們做以下事情:

  • 處理Adapter 中ImageView的回收和取消下載。
  • 使用最小的內存 來做復雜的圖片變換。比如高斯模糊,圓角、圓形等處理。
  • 自動幫我們緩存圖片。內存和磁盤緩存。

以上只是列出了Picasso 比較核心的幾點,其實它的優點遠遠不止這些,接下來就看一下如何使用Picasso。

Picasso-Android.png

本文目錄

0,添加依賴
1, 加載顯示圖片
2,Placeholder & noPlaceholder & noFade
3, 設置圖片尺寸(Resize)、縮放(Scale)和裁剪(Crop)
4,圖片旋轉Rotation()
5, 轉換器Transformation
6,請求優先級
7,Tag管理請求
8,同步/異步加載圖片
9,緩存(Disk 和 Memory)
10,Debug 和日志
11,Picasso 擴展

正文

0. 添加依賴

要使用Picasso,首先我們要添加版本依賴,去官網或者Github 看一下當前的最新版本(截止本文最新版本為2.5.2),然后在build.gradle中添加依賴:

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

1. 加載顯示圖片

將Picasso添加到項目之后,我們就可以用它來加載圖片了,使用方法非常簡單:

 Picasso.with(this)
        .load("http://ww3.sinaimg.cn/large/610dc034jw1fasakfvqe1j20u00mhgn2.jpg")
        .into(mImageView);

只需要一行代碼就完成了加載圖片到顯示的整個過程,鏈式調用,非常簡潔,其實有三步,一次調用了三個方法:

  • with(Context) 獲取一個Picasso單例,參數是一個Context上下文
  • load(String) 調用load 方法加載圖片
  • into (ImageView) 將圖片顯示在對應的View上,可以是ImageView,也可以是實現了Target j接口的自定義View。

上面演示了加載一張網絡圖片,它還支持其它形式的圖片加載,加載文件圖片,加載本地資源圖片,加載一個Uri 路徑給的圖片,提供了幾個重載的方法:

1, load(Uri uri) 加載一個以Uri路徑給的圖片

Uri uri = Uri.parse(ANDROID_RESOURCE + context.getPackageName() + FOREWARD_SLASH + resourceId)

Picasso.with(this).load(uri).into(mImageView);

** 2,load(File file) 加載File中的圖片**

 Picasso.with(this).load(file).into(mImageView);

3, load(int resourceId) 加載本地資源圖片

Picasso.with(this).load(R.mipmap.ic_launcher).into(mImageView);

提醒:上面介紹了load的幾個重載方法,加載不同資源的圖片,另外提醒注意一下load(String path)接受String 參數的這個方法,參數String 可以是一個網絡圖片url,也可以是file 路徑、content資源 和Android Resource。看一下源碼的注釋。

/**
   * Start an image request using the specified path. This is a convenience method for calling
   * {@link #load(Uri)}.
   * <p>
   * This path may be a remote URL, file resource (prefixed with {@code file:}), content resource
   * (prefixed with {@code content:}), or android resource (prefixed with {@code
   * android.resource:}.
   * <p>
   * Passing {@code null} as a {@code path} will not trigger any request but will set a
   * placeholder, if one is specified.
   *
   * @see #load(Uri)
   * @see #load(File)
   * @see #load(int)
   * @throws IllegalArgumentException if {@code path} is empty or blank string.
   */
  public RequestCreator load(String path) {
    if (path == null) {
      return new RequestCreator(this, null, 0);
    }
    if (path.trim().length() == 0) {
      throw new IllegalArgumentException("Path must not be empty.");
    }
    return load(Uri.parse(path));
  }

要使用string 參數加載上面的幾種資源,除了網絡url,其它幾種需要加上對應前綴,file文件路徑前綴:file: , content 添加前綴:content: ,Android Resource 添加:android.resource:

2. placeholder& error & noPlaceholder & noFade

通過上面的第一步我們就可以通過Picasso 加載圖片了,我們的項目中通常最常用的就是加載網絡圖片,但是由于網絡環境的差異,有時侯加載網絡圖片的過程有點慢,這樣界面上就會顯示空ImageView什么也看不見,用戶體驗非常不好。其實以前用過ImageLoader的同學都知道,ImageLoader 是可以設置加載中顯示默認圖片的,Picasso當然也給我們提供了這個功能,這就是我們要說的placeholder(占位圖)。

1,placeholder
placeholder提供一張在網絡請求還沒有完成時顯示的圖片,它必須是本地圖片,代碼如下:

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .into(mImageView);

設置placeholder之后,在加載圖片的時候,就可以顯示設置的默認圖了,提升用戶體驗。
2, error
和placeholder 的用法一樣,error 提供一張在加載圖片出錯的情況下顯示的默認圖


        Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .into(mImageView);

3,noPlaceholder
這個方法的意思就是:在調用into的時候明確告訴你沒有占位圖設置。根據這個方法簽名的解釋是阻止View被回收的時候Picasso清空target或者設置一個應用的占位圖。需要注意的是placeholder和noPlaceholder 不能同時應用在同一個請求上,會拋異常。


        Picasso.with(this).load(URL)
                .noPlaceholder()
                .error(R.drawable.error_iamge)
                .into(mImageView);

4,noFade
無論你是否設置了占位圖,Picasso 從磁盤或者網絡加載圖片時,into 顯示到ImageView 都會有一個簡單的漸入過度效果,讓你的UI視覺效果更柔順絲滑一點,如果你不要這個漸入的效果(沒有這么坑爹的需求吧!!!),就調用noFade方法。

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .noFade()
                .into(mImageView);

3. 設置圖片尺寸(Resize)、縮放(Scale)和裁剪(Crop)

1, Resize(int w,int h)
在項目中,為了帶寬、內存使用和下載速度等考慮,服務端給我們的圖片的size 應該和我們View 實際的size一樣的,但是實際情況并非如此,服務端可能給我們一些奇怪的尺寸的圖片,我們可以使用resize(int w,int hei) 來重新設置尺寸。

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .resize(400,200)
                .into(mImageView);

resize()方法接受的參數的單位是pixels,還有一個可以設置dp單位的方法,將你的尺寸寫在dimens.xml文件中,然后用resizeDimen(int targetWidthResId, int targetHeightResId)方法

 <dimen name="image_width">300dp</dimen>
 <dimen name="image_height">200dp</dimen>
 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .resizeDimen(R.dimen.image_width,R.dimen.image_height)
                .into(mImageView);

2,onlyScaleDown
當調用了resize 方法重新設置圖片尺寸的時候,調用onlyScaleDown 方法,只有當原始圖片的尺寸大于我們指定的尺寸時,resize才起作用,如:

  Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .resize(4000,2000)
                .onlyScaleDown()
                .into(mImageView);

只有當原來的圖片尺寸大于4000 x 2000的時候,resize 才起作用。
3,圖片裁剪 centerCrop()
這個屬性應該不陌生吧!ImageView 的ScaleType 就有這個屬性。當我們使用resize 來重新設置圖片的尺寸的時候,你會發現有些圖片拉伸或者扭曲了(使用ImageView的時候碰到過吧),我要避免這種情況,Picasso 同樣給我們提供了一個方法,centerCrop,充滿ImageView 的邊界,居中裁剪

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .resize(400,200)
                .centerCrop()
                .into(mImageView);

4,centerInside
上面的centerCrop是可能看不到全部圖片的,如果你想讓View將圖片展示完全,可以用centerInside,但是如果圖片尺寸小于View尺寸的話,是不能充滿View邊界的。

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .resize(400,200)
                .centerInside()
                .into(mImageView);

5,fit
fit 是干什的呢?上面我們需要用resize()來指定我們需要的圖片的尺寸,那就是說在程序中需要我們計算我們需要的尺寸(固定大小的除外),這樣很麻煩,fit 方法就幫我們解決了這個問題。fit 它會自動測量我們的View的大小,然后內部調用reszie方法把圖片裁剪到View的大小,這就幫我們做了計算size和調用resize 這2步。非常方便。代碼如下:

Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .fit()
                .into(mImageView);

使用fit 還是會出現拉伸扭曲的情況,因此最好配合前面的centerCrop使用,代碼如下:

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .fit()
                .centerCrop()
                .into(mImageView);

看一下對比圖:
fit(會拉伸):

image_fit.png

fit & centerCrop (不會拉伸):

fit_centerCrop.png

注意:特別注意,
1,fit 只對ImageView 有效
2,使用fit時,ImageView 寬和高不能為wrap_content,很好理解,因為它要測量寬高。

4. 圖片旋轉Rotation()

在圖片顯示到ImageView 之前,還可以對圖片做一些旋轉操作,調用rotate(int degree)方法

Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .rotate(180)
                .into(mImageView);

這個方法它是以(0,0)點旋轉,但是有些時候我們并不想以(0,0)點旋轉,還提供了另外一個方法可以指定原點:

  • rotate(float degrees, float pivotX, float pivotY) 以(pivotX, pivotY)為原點旋轉
 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .rotate(180,200,100)
                .into(mImageView);

5. 轉換器Transformation

Transformation 這就是Picasso的一個非常強大的功能了,它允許你在load圖片 -> into ImageView 中間這個過成對圖片做一系列的變換。比如你要做圖片高斯模糊、添加圓角、做度灰處理、圓形圖片等等都可以通過Transformation來完成。

來看一個高斯模糊的例子:

1,首先定義一個轉換器繼承 Transformation

 public static class BlurTransformation implements Transformation{

        RenderScript rs;

        public BlurTransformation(Context context) {
            super();
            rs = RenderScript.create(context);
        }

        @Override
        public Bitmap transform(Bitmap bitmap) {
            // Create another bitmap that will hold the results of the filter.
            Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            // Allocate memory for Renderscript to work with
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
            Allocation output = Allocation.createTyped(rs, input.getType());

            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setInput(input);

            // Set the blur radius
            script.setRadius(25);

            // Start the ScriptIntrinisicBlur
            script.forEach(output);

            // Copy the output to the blurred bitmap
            output.copyTo(blurredBitmap);

            bitmap.recycle();

            return blurredBitmap;
        }

        @Override
        public String key() {
            return "blur";
        }
    }

2, 加載圖片的時候,在into 方法前面調用 transform方法 應用Transformation

  Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .transform(new BlurTransformation(this))
                .into(mBlurImage);

看一下效果圖:

transformation.png

上面為原圖,下面為高斯模糊圖

是不是很強大,任何復雜的變換都可以通過Transformation 來做。

還不止于此,還有更強大的功能。可以在一個請求上應用多個Transformation

比如:我想先做個度灰處理然后在做一個高斯模糊圖:

1, 度灰的Transformation

 public static class GrayTransformation implements Transformation{

        @Override
        public Bitmap transform(Bitmap source) {
            int width, height;
            height = source.getHeight();
            width = source.getWidth();

            Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            Canvas c = new Canvas(bmpGrayscale);
            Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
            paint.setColorFilter(f);
            c.drawBitmap(source, 0, 0, paint);

            if(source!=null && source!=bmpGrayscale){
                source.recycle();
            }
            return bmpGrayscale;
        }

        @Override
        public String key() {
            return "gray";
        }
    }

2, 如果是多個Transformation操作,有2種方式應用
方式一:直接調用多次transform 方法,不會覆蓋的。它只是保存到了一個List 里面

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .fit()
                .centerCrop()
                .transform(new GrayTransformation())//度灰處理
                .transform(new BlurTransformation(this))//高斯模糊
                .into(mBlurImage);

需要注意調用的順序
方式二:接受一個List,將Transformation 放大list 里

        List<Transformation> transformations = new ArrayList<>();
        transformations.add(new GrayTransformation());
        transformations.add(new BlurTransformation(this));

        Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .fit()
                .centerCrop()
                .transform(transformations)
                .into(mBlurImage);

效果圖:

gray_blur.png

如上圖,第一張為度灰操作,第二張為 度灰+高斯模糊

另外發現了一個開源庫,專門寫了很多好玩的Transformation,有興趣的可以看一下:
picasso-transformations

6. 請求優先級

Picasso 為請求設置有優先級,有三種優先級,LOW、NORMAL、HIGH。默認情況下都是NORMAL,除了調用fetch 方法,fetch 方法的優先級是LOW。

public enum Priority {
    LOW,
    NORMAL,
    HIGH
  }

可以通過priority方法設置請求的優先級,這會影響請求的執行順序,但是這是不能保證的,它只會往高的優先級靠攏。代碼如下:

 Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .priority(Picasso.Priority.HIGH)
               // .priority(Picasso.Priority.LOW)
                .into(mImageView);

7. Tag管理請求

Picasso 允許我們為一個請求設置tag來管理請求,看一下對應的幾個方法:
下面3個方法是Picasso這個類的:

  • cancelTag(Object tag) 取消設置了給定tag的所有請求
  • pauseTag(Object tag) 暫停設置了給定tag 的所有請求
  • resumeTag(Object tag) resume 被暫停的給定tag的所有請求

還有一個方法是RequestCreator的:

  • tag(Object tag) 為請求設置tag

幾個方法的意思也很明確,就是我們可以暫停、resume、和取消請求,可以用在哪些場景呢?

場景一: 比如一個照片流列表,當我們快速滑動列表瀏覽照片的時候,后臺會一直發起請求加載照片的,這可能會導致卡頓,那么我們就可以為每個請求設置一個相同的Tag,在快速滑動的時候,調用pauseTag暫停請求,當滑動停止的時候,調用resumeTag恢復請求,這樣的體驗是不是就會更好一些呢。

Adapter中添加如下代碼:

Picasso.with(this).load(mData.get(position))
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .tag("PhotoTag")
                .into(holder.mImageView);

Activity中為RecyclerView添加滑動監聽:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                final Picasso picasso = Picasso.with(MainActivity.this);

                if (newState == SCROLL_STATE_IDLE) {
                    picasso.resumeTag("PhotoTag");
                } else {
                    picasso.pauseTag("PhotoTag");
                }
            }
        });

場景二: 比如一個照片流列表界面,在弱網環境下,加載很慢,退出這個界面時可能會有很多請求沒有完成,這個時候我們就可 以通過tag 來取消請求了。

 @Override
    protected void onDestroy() {
        super.onDestroy();
        Picasso.with(this).cancelTag("PhotoTag");
    }

8. 同步/異步加載圖片

Picasso 加載圖片也有同步/異步兩種方式
**1,get() 同步 **
很簡單,同步加載使用get() 方法,返回一個Bitmap 對象,代碼如下:

 try {
           Bitmap bitmap =  Picasso.with(this).load(URL).get();
        } catch (IOException e) {
            e.printStackTrace();
        }

注意:使用同步方式加載,不能放在主線程來做。

2,異步的方式加載圖片,fetch()
一般直接加載圖片通過into顯示到ImageView 是異步的方式,除此之外,還提供了2個異步的方法:

  • fetch() 異步方式加載圖片
  • fetch(Callback callback) 異步方式加載圖片并給一個回調接口。
  Picasso.with(this).load(URL).fetch(new Callback() {
            @Override
            public void onSuccess() {
                //加載成功
            }

            @Override
            public void onError() {
              //加載失敗
            }
        });

這里就要吐槽一下接口設計了,回調并沒有返回Bitmap, 不知道作者是怎么考慮的,只是一個通知效果,知道請求失敗還是成功。
**fetch 方法異步加載圖片并沒有返回Bitmap,這個方法在請求成功之后,將結果存到了緩存,包括磁盤和內存緩存。所以使用這種方式加載圖片適用于這種場景:知道稍后會加載圖片,使用fetch 先加載緩存,起到一個預加載的效果。 **

9. 緩存(Disk 和 Memory)

Picasso 有內存緩存(Memory)和磁盤緩存( Disk), 首先來看一下源碼中對于緩存的介紹:

  • LRU memory cache of 15% the available application RAM
  • Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only
    available on API 14+ <em>or</em> if you are using a standalone library that provides a disk cache on all API levels like OkHttp)
  • Three download threads for disk and network access.

可以看出,內存緩存是使用的LRU 策略的緩存實現,它的大小是內存大小的15%,可以自定義它的大小,最后在擴展那一章節再講,磁盤緩存是磁盤容量的2%但是不超過50M,不少于5M。處理一個請求的時候,按照這個順訊檢查:memory->disk->network 。先檢查有木有內存緩存,如果命中,直接返回結果,否則檢查磁盤緩存,命中則返回結果,沒有命中則從網上獲取。

默認情況下,Picasso 內存緩存和磁盤緩存都開啟了的,也就是加載圖片的時候,內存和磁盤都緩存了,但是有些時候,我們并不需要緩存,比如說:加載一張大圖片的時候,如果再內存中保存一份,很容易造成OOM,這時候我們只希望有磁盤緩存,而不希望緩存到內存,因此就需要我們設置緩存策略了。Picasso 提供了這樣的方法。

1,memoryPolicy 設置內存緩存策略
就像上面所說的,有時候我們不希望有內存緩存,我們可以通過 memoryPolicy 來設置。MemoryPolicy是一個枚舉,有兩個值

NO_CACHE:表示處理請求的時候跳過檢查內存緩存
**NO_STORE: ** 表示請求成功之后,不將最終的結果存到內存。

示例代碼如下:

with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE) //靜止內存緩存
                .into(mBlurImage);

2,networkPolicy 設置磁盤緩存策略
和內存緩存一樣,加載一張圖片的時候,你也可以跳過磁盤緩存,和內存緩存策略的控制方式一樣,磁盤緩存調用方法networkPolicy(NetworkPolicy policy, NetworkPolicy... additional) , NetworkPolicy是一個枚舉類型,有三個值:

NO_CACHE: 表示處理請求的時候跳過處理磁盤緩存
** NO_STORE:** 表示請求成功后,不將結果緩存到Disk,但是這個只對OkHttp有效。
OFFLINE: 這個就跟 上面兩個不一樣了,如果networkPolicy方法用的是這個參數,那么Picasso會強制這次請求從緩存中獲取結果,不會發起網絡請求,不管緩存中能否獲取到結果。

使用示例:

 with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)//跳過內存緩存
                .networkPolicy(NetworkPolicy.NO_CACHE)//跳過磁盤緩存
                .into(mBlurImage);

強制從緩存獲取:

 with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .networkPolicy(NetworkPolicy.OFFLINE)//強制從緩存獲取結果
                .into(mBlurImage);

10. Debug 和日志

1,緩存指示器

上一節說了,Picasso 有內存緩存和磁盤緩存,先從內存獲取,沒有再去磁盤緩存獲取,都有就從網絡加載,網絡加載是比較昂貴和耗時的。因此,作為一個開發者,我們往往需要加載的圖片是從哪兒來的(內存、Disk還是網絡),Picasso讓我們很容易就實現了。只需要調用一個方法setIndicatorsEnabled(boolean)就可以了,它會在圖片的左上角出現一個帶色塊的三角形標示,有3種顏色,綠色表示從內存加載、藍色表示從磁盤加載、紅色表示從網絡加載。

 Picasso.with(this)
        .setIndicatorsEnabled(true);//顯示指示器

效果圖:

cache_indicator.png

如上圖所示,第一張圖從網絡獲取,第二張從磁盤獲取,第三張圖從內存獲取。

看一下源碼中定義指示器的顏色:

 /** Describes where the image was loaded from. */
  public enum LoadedFrom {
    MEMORY(Color.GREEN),
    DISK(Color.BLUE),
    NETWORK(Color.RED);

    final int debugColor;

    private LoadedFrom(int debugColor) {
      this.debugColor = debugColor;
    }
  }

可以很清楚看出,對應三種顏色代表著圖片的來源。

2,日志
上面的指示器能夠很好的幫助我們看出圖片的來源,但是有時候我們需要更詳細的信息,Picasso,可以打印一些日志,比如一些關鍵方法的執行時間等等,我們只需要調用setLoggingEnabled(true)方法,然后App在加載圖片的過程中,我們就可以從logcat 看到一些關鍵的日志信息。

   Picasso.with(this)
          .setLoggingEnabled(true);//開啟日志打印

11. Picasso 擴展

到目前為止,Picasso的基本使用已經講得差不多了,但是在實際項目中我們這可能還滿足不了我們的需求,我們需要對它做一些自己的擴展,比如我們需要換緩存的位置、我們需要擴大緩存、自定義線程池、自定義下載器等等。這些都是可以的,接下來我們來看一下可以做哪些方面的擴展。

1,用Builder 自己構造一個Picasso Instance
我們來回顧一下前面是怎么用Picasso 加載圖片的:

Picasso.with(this)
       .load("http://ww3.sinaimg.cn/large/610dc034jw1fasakfvqe1j20u00mhgn2.jpg")
       .into(mImageView);

總共3步:
1,用with方法獲取一個Picasso 示例
2,用load方法加載圖片
3,用into 放法顯示圖片

首先Picasso是一個單例模式,我們每一次獲取的示例都是默認提供給我們的實例。但是也可以不用它給的Instance,我們直接用builder來構造一個Picasso:

       Picasso.Builder builder = new Picasso.Builder(this);
        //構造一個Picasso
        Picasso picasso = builder.build();
        //加載圖片
        picasso.load(URL)
                .into(mImageView);

這樣我們就構造了一個局部的Picasso實例,當然了,我們直接用new 了一個builder,然后build()生成了一個Picasso。這跟默認的通過with方法獲取的實例是一樣的。那么現在我們就可以配置一些自定義的功能了。
2, 配置自定義下載器 downLoader
如果我們不想用默認提供的Downloader,那么我們可以自定義一個下載器然后配置進去。舉個例子:

(1) 先自定義一個Downloader(只是舉個例子,并沒有實現):

/**
 * Created by zhouwei on 17/2/26.
 */

public class CustomDownloader implements Downloader {

    @Override
    public Response load(Uri uri, int networkPolicy) throws IOException {
        return null;
    }

    @Override
    public void shutdown() {

    }
}

(2) 然后通過builder 配置:

        //配置下載器
        builder.downloader(new CustomDownloader());
        //構造一個Picasso
        Picasso picasso = builder.build();

這樣配置后,我們用build()生成的Picasso 實例來加載圖片就會使用自定義的下載器來下載圖片了。

** 3, 配置緩存**
前面說過,內存緩存是用的LRU Cahce ,大小是手機內存的15% ,如果你想緩存大小更大一點或者更小一點,可以自定義,然后配置。

        //配置緩存
        LruCache cache = new LruCache(5*1024*1024);// 設置緩存大小
        builder.memoryCache(cache);

上面只是一個簡單的舉例,當然了你可以自定義,也可以使用LRUCache,改變大小,改變存儲路徑等等。

提示: 很遺憾,好像沒有提供改變磁盤緩存的接口,那就只能用默認的了。

4, 配置線程池
Picasso 默認的線程池的核心線程數為3,如果你覺得不夠用的話,可以配置自己需要的線程池,舉個列子:

        //配置線程池
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        builder.executor(executorService);

**5, 配置全局的 Picasso Instance **
上面說的這些自定義配置項目都是應用在一個局部的Picasso instance 上的,我們不可能每一次使用都要重新配置一下,這樣就太麻煩了。我們希望我們的這些自定義配置能在整個項目都應用上,并且只配置一次。其實Picasso 給我們提供了這樣的方法。可以調用setSingletonInstance(Picasso picasso)就可以了,看一下這個方法的源碼:

 /**
   * Set the global instance returned from {@link #with}.
   * <p>
   * This method must be called before any calls to {@link #with} and may only be called once.
   */
  public static void setSingletonInstance(Picasso picasso) {
    synchronized (Picasso.class) {
      if (singleton != null) {
        throw new IllegalStateException("Singleton instance already exists.");
      }
      singleton = picasso;
    }
  }

設置一個通過with方法返回的全局instance。我們只希望配置一次,所以,我們應該在Application 的onCreate方法中做全局配置就可以了。app一啟動就配置好,然后直接和前面的使用方法一樣,調用with方法獲取Picasso instance 加載圖片就OK了。

因此在Application 中添加如下代碼:

 @Override
    public void onCreate() {
        super.onCreate();
        
        // 配置全局的Picasso instance 
        
        Picasso.Builder builder = new Picasso.Builder(this);
        //配置下載器
        builder.downloader(new CustomDownloader());
        //配置緩存
        LruCache cache = new LruCache(5*1024*1024);// 設置緩存大小
        builder.memoryCache(cache);
        //配置線程池
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        builder.executor(executorService);

        //構造一個Picasso
        Picasso picasso = builder.build();
        // 設置全局單列instance 
        Picasso.setSingletonInstance(picasso);
        
        
    }

然后應用這些自定義配置加載圖片

Picasso.with(this).load("http://ww3.sinaimg.cn/large/610dc034jw1fasakfvqe1j20u00mhgn2.jpg").into(mImageView);

用法和以前的一樣,但是我們已經將我們的自定義配置應用上了。

結尾

以上就是對Picasso 用法的全部總結,如有什么問題,歡迎留言指正。Picasso真的是一個強大的圖片加載緩存庫,API 簡單好用,而且是鏈式調用的(這點我特別喜歡)。官方文檔寫的比較簡單,很多用法都要看源碼和注釋才知道。希望本文能給才開始使用Picasso 的同學一點幫助。

參考

Picasso官網
Picasso — Getting Started

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容