寫在前面
Android 中有幾個比較有名的圖片載入框架,Universal ImageLoader、Picasso、Glide和Fresco。它們各有優點,以前一直用的是ImageLoader 做專案中的圖片載入,由於作者宣佈ImageLoader 不會在更新了,因此新的專案打算換一個圖片載入框架-Picasso, Picasso 是Square 公司開源的Android 端的圖片載入和快取框架。Square 真是一家良心公司啊,為我們Android開發者貢獻了很多優秀的開源專案有木有!像什麼Rerefoit 、OkHttp、LeakCanary、Picasso等等都是非常火的開源專案。扯遠了,回到正題,除了使用簡單方便,Picasso還能自動幫我們做以下事情:
- 處理Adapter 中ImageView的回收和取消下載。
- 使用最小的記憶體 來做複雜的圖片變換。比如高斯模糊,圓角、圓形等處理。
- 自動幫我們快取圖片。記憶體和磁碟快取。
以上只是列出了Picasso 比較核心的幾點,其實它的優點遠遠不止這些,接下來就看一下如何使用Picasso。
本文目錄
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(會拉伸):
fit & centerCrop (不會拉伸):
注意:特別注意,
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 來做。
還不止於此,還有更強大的功能。可以在一個請求上應用多個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);複製程式碼
效果圖:
如上圖,第一張為度灰操作,第二張為 度灰+高斯模糊
另外發現了一個開源庫,專門寫了很多好玩的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+ or 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);//顯示指示器複製程式碼
效果圖:
如上圖所示,第一張圖從網路獲取,第二張從磁碟獲取,第三張圖從記憶體獲取。
看一下原始碼中定義指示器的顏色:
/** 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 的同學一點幫助。