Picasso 是Square 公司開源的Android 端的圖片加載和緩存框架。Square 真是一家良心公司啊,爲咱們Android開發者貢獻了不少優秀的開源項目有木有!像什麼Rerefoit 、OkHttp、LeakCanary、Picasso等等都是很是火的開源項目。回到正題,除了使用簡單方便,Picasso還能自動幫咱們作如下事情:android
以上只是列出了Picasso 比較核心的幾點,其實它的優勢遠遠不止這些,接下來就看一下如何使用Picasso。git
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 擴展github
要使用Picasso,首先咱們要添加版本依賴,去官網或者Github 看一下當前的最新版本(截止本文最新版本爲2.5.2),而後在build.gradle中添加依賴:緩存
將Picasso添加到項目以後,咱們就能夠用它來加載圖片了,使用方法很是簡單:網絡
只須要一行代碼就完成了加載圖片到顯示的整個過程,鏈式調用,很是簡潔,其實有三步,一次調用了三個方法:app
上面演示了加載一張網絡圖片,它還支持其它形式的圖片加載,加載文件圖片,加載本地資源圖片,加載一個Uri 路徑給的圖片,提供了幾個重載的方法:框架
load(Uri uri) 加載一個以Uri路徑給的圖片less
load(File file) 加載File中的圖片異步
load(int resourceId) 加載本地資源圖片ide
提醒:上面介紹了load的幾個重載方法,加載不一樣資源的圖片,另外提醒注意一下load(String path)接受String 參數的這個方法,參數String 能夠是一個網絡圖片url,也能夠是file 路徑、content資源 和Android Resource。看一下源碼的註釋。
要使用string 參數加載上面的幾種資源,除了網絡url,其它幾種須要加上對應前綴,file文件路徑前綴:file: , content 添加前綴:content: ,Android Resource 添加:android.resource:
經過上面的第一步咱們就能夠經過Picasso 加載圖片了,咱們的項目中一般最經常使用的就是加載網絡圖片,可是因爲網絡環境的差別,有時侯加載網絡圖片的過程有點慢,這樣界面上就會顯示空ImageView什麼也看不見,用戶體驗很是很差。其實之前用過ImageLoader的同窗都知道,ImageLoader 是能夠設置加載中顯示默認圖片的,Picasso固然也給咱們提供了這個功能。
placeholder
placeholder提供一張在網絡請求尚未完成時顯示的圖片,它必須是本地圖片,代碼以下:
設置placeholder以後,在加載圖片的時候,就能夠顯示設置的默認圖了,提高用戶體驗。
error
和placeholder 的用法同樣,error 提供一張在加載圖片出錯的狀況下顯示的默認圖
noPlaceholder
這個方法的意思就是:在調用into的時候明確告訴你沒有佔位圖設置。根據這個方法簽名的解釋是阻止View被回收的時候Picasso清空target或者設置一個應用的佔位圖。須要注意的是placeholder和noPlaceholder 不能同時應用在同一個請求上,會拋異常。
noFade
不管你是否設置了佔位圖,Picasso 從磁盤或者網絡加載圖片時,into 顯示到ImageView 都會有一個簡單的漸入過分效果,讓你的UI視覺效果更柔順絲滑一點,若是你不要這個漸入的效果,就調用noFade方法。
Resize(int w,int h)
在項目中,爲了帶寬、內存使用和下載速度等考慮,服務端給咱們的圖片的size 應該和咱們View 實際的size同樣的,可是實際狀況並不是如此,服務端可能給咱們一些奇怪的尺寸的圖片,咱們可使用resize(int w,int hei) 來從新設置尺寸。
resize()方法接受的參數的單位是pixels,還有一個能夠設置dp單位的方法,將你的尺寸寫在dimens.xml文件中,而後用resizeDimen(int targetWidthResId, int targetHeightResId)
方法
onlyScaleDown
當調用了resize 方法從新設置圖片尺寸的時候,調用onlyScaleDown 方法,只有當原始圖片的尺寸大於咱們指定的尺寸時,resize才起做用,如:
只有當原來的圖片尺寸大於4000 x 2000的時候,resize 才起做用。
圖片裁剪 centerCrop()
這個屬性應該不陌生吧!ImageView 的ScaleType 就有這個屬性。當咱們使用resize 來從新設置圖片的尺寸的時候,你會發現有些圖片拉伸或者扭曲了(使用ImageView的時候碰到過吧),我要避免這種狀況,Picasso 一樣給咱們提供了一個方法,centerCrop,充滿ImageView 的邊界,居中裁剪。
centerInside
上面的centerCrop是可能看不到所有圖片的,若是你想讓View將圖片展現徹底,能夠用centerInside,可是若是圖片尺寸小於View尺寸的話,是不能充滿View邊界的。
fit
fit 是幹什的呢?上面咱們須要用resize()來指定咱們須要的圖片的尺寸,那就是說在程序中須要咱們計算咱們須要的尺寸(固定大小的除外),這樣很麻煩,fit 方法就幫咱們解決了這個問題。fit 它會自動測量咱們的View的大小,而後內部調用reszie方法把圖片裁剪到View的大小,這就幫咱們作了計算size和調用resize 這2步。很是方便。代碼以下:
使用fit 仍是會出現拉伸扭曲的狀況,所以最好配合前面的centerCrop使用,代碼以下:
看一下對比圖:
fit(會拉伸):
fit & centerCrop (不會拉伸):
注意:特別注意,
1,fit 只對ImageView 有效
2,使用fit時,ImageView 寬和高不能爲wrap_content,很好理解,由於它要測量寬高。
在圖片顯示到ImageView 以前,還能夠對圖片作一些旋轉操做,調用rotate(int degree)
方法
這個方法它是以(0,0)點旋轉,可是有些時候咱們並不想以(0,0)點旋轉,還提供了另一個方法能夠指定原點:
Transformation 這就是Picasso的一個很是強大的功能了,它容許你在load圖片 -> into ImageView 中間這個過成對圖片作一系列的變換。好比你要作圖片高斯模糊、添加圓角、作度灰處理、圓形圖片等等均可以經過Transformation來完成。
來看一個高斯模糊的例子:
第一步, 首先定義一個轉換器繼承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"; } }
第二步, 加載圖片的時候,在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
好比:我想先作個度灰處理而後在作一個高斯模糊圖:
第一步, 定義一個度灰的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"; } }
第二步, 若是是多個Transformation操做,有兩種方式應用
方式一:直接調用屢次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
Picasso 爲請求設置有優先級,有三種優先級,LOW、NORMAL、HIGH。默認狀況下都是NORMAL,除了調用fetch 方法,fetch 方法的優先級是LOW。
能夠經過priority方法設置請求的優先級,這會影響請求的執行順序,可是這是不能保證的,它只會往高的優先級靠攏。代碼以下:
Picasso 容許咱們爲一個請求設置tag來管理請求,看一下對應的幾個方法:
下面3個方法是Picasso這個類的:
還有一個方法是RequestCreator的:
幾個方法的意思也很明確,就是咱們能夠暫停、resume、和取消請求,能夠用在哪些場景呢?
場景一: 好比一個照片流列表,當咱們快速滑動列表瀏覽照片的時候,後臺會一直髮起請求加載照片的,這可能會致使卡頓,那麼咱們就能夠爲每一個請求設置一個相同的Tag,在快速滑動的時候,調用pauseTag暫停請求,當滑動中止的時候,調用resumeTag恢復請求,這樣的體驗是否是就會更好一些呢。
Adapter中添加以下代碼:
Activity中爲RecyclerView添加滑動監聽:
場景二: 好比一個照片流列表界面,在弱網環境下,加載很慢,退出這個界面時可能會有不少請求沒有完成,這個時候咱們就可 以經過tag 來取消請求了。
Picasso 加載圖片也有同步/異步兩種方式
同步get()
很簡單,同步加載使用get() 方法,返回一個Bitmap 對象,代碼以下:
注意:使用同步方式加載,不能放在主線程來作。
異步fetch()
通常直接加載圖片經過into顯示到ImageView 是異步的方式,除此以外,還提供了2個異步的方法:
這裏就要吐槽一下接口設計了,回調並無返回Bitmap, 不知道做者是怎麼考慮的,只是一個通知效果,知道請求失敗仍是成功。
**fetch 方法異步加載圖片並無返回Bitmap,這個方法在請求成功以後,將結果存到了緩存,包括磁盤和內存緩存。因此使用這種方式加載圖片適用於這種場景:知道稍後會加載圖片,使用fetch 先加載緩存,起到一個預加載的效果。 **
Picasso 有內存緩存(Memory)和磁盤緩存( Disk), 首先來看一下源碼中對於緩存的介紹:
能夠看出,內存緩存是使用的LRU 策略的緩存實現,它的大小是內存大小的15%,能夠自定義它的大小,最後在擴展那一章節再講,磁盤緩存是磁盤容量的2%可是不超過50M,很多於5M。處理一個請求的時候,按照這個順訊檢查:memory->disk->network 。先檢查有木有內存緩存,若是命中,直接返回結果,不然檢查磁盤緩存,命中則返回結果,沒有命中則從網上獲取。
默認狀況下,Picasso 內存緩存和磁盤緩存都開啓了的,也就是加載圖片的時候,內存和磁盤都緩存了,可是有些時候,咱們並不須要緩存,好比說:加載一張大圖片的時候,若是再內存中保存一份,很容易形成OOM,這時候咱們只但願有磁盤緩存,而不但願緩存到內存,所以就須要咱們設置緩存策略了。Picasso 提供了這樣的方法。
方式一:memoryPolicy 設置內存緩存策略
就像上面所說的,有時候咱們不但願有內存緩存,咱們能夠經過 memoryPolicy 來設置。MemoryPolicy是一個枚舉,有兩個值
NO_CACHE:表示處理請求的時候跳過檢查內存緩存
**NO_STORE: ** 表示請求成功以後,不將最終的結果存到內存。
示例代碼以下:
方式二:networkPolicy 設置磁盤緩存策略
和內存緩存同樣,加載一張圖片的時候,你也能夠跳過磁盤緩存,和內存緩存策略的控制方式同樣,磁盤緩存調用方法networkPolicy(NetworkPolicy policy, NetworkPolicy... additional)
, NetworkPolicy是一個枚舉類型,有三個值:
NO_CACHE: 表示處理請求的時候跳過處理磁盤緩存
NO_STORE:表示請求成功後,不將結果緩存到Disk,可是這個只對OkHttp有效。
OFFLINE: 這個就跟 上面兩個不同了,若是networkPolicy方法用的是這個參數,那麼Picasso會強制此次請求從緩存中獲取結果,不會發起網絡請求,無論緩存中可否獲取到結果。
使用示例:
強制從緩存獲取:
緩存指示器
上一節說了,Picasso 有內存緩存和磁盤緩存,先從內存獲取,沒有再去磁盤緩存獲取,都有就從網絡加載,網絡加載是比較昂貴和耗時的。所以,做爲一個開發者,咱們每每須要加載的圖片是從哪兒來的(內存、Disk仍是網絡),Picasso讓咱們很容易就實現了。只須要調用一個方法setIndicatorsEnabled(boolean)
就能夠了,它會在圖片的左上角出現一個帶色塊的三角形標示,有3種顏色,綠色表示從內存加載、藍色表示從磁盤加載、紅色表示從網絡加載。
效果圖:
如上圖所示,第一張圖從網絡獲取,第二張從磁盤獲取,第三張圖從內存獲取。
看一下源碼中定義指示器的顏色:
能夠很清楚看出,對應三種顏色表明着圖片的來源。
日誌
上面的指示器可以很好的幫助咱們看出圖片的來源,可是有時候咱們須要更詳細的信息,Picasso,能夠打印一些日誌,好比一些關鍵方法的執行時間等等,咱們只須要調用setLoggingEnabled(true)
方法,而後App在加載圖片的過程當中,咱們就能夠從logcat 看到一些關鍵的日誌信息。
到目前爲止,Picasso的基本使用已經講得差很少了,可是在實際項目中咱們這可能還知足不了咱們的需求,咱們須要對它作一些本身的擴展,好比咱們須要換緩存的位置、咱們須要擴大緩存、自定義線程池、自定義下載器等等。這些都是能夠的,接下來咱們來看一下能夠作哪些方面的擴展。
用Builder 本身構造一個Picasso Instance
咱們來回顧一下前面是怎麼用Picasso 加載圖片的:
總共3步:
(1) 用with方法獲取一個Picasso 示例
(2) 用load方法加載圖片
(3) 用into 放法顯示圖片
首先Picasso是一個單例模式,咱們每一次獲取的示例都是默認提供給咱們的實例。可是也能夠不用它給的Instance,咱們直接用builder來構造一個Picasso:
這樣咱們就構造了一個局部的Picasso實例,固然了,咱們直接用new 了一個builder,而後build()生成了一個Picasso。這跟默認的經過with方法獲取的實例是同樣的。那麼如今咱們就能夠配置一些自定義的功能了。
配置自定義下載器 downLoader
若是咱們不想用默認提供的Downloader,那麼咱們能夠自定義一個下載器而後配置進去。舉個例子:
總共5步:
(1) 先自定義一個Downloader(只是舉個例子,並無實現):
(2) 而後經過builder 配置:
這樣配置後,咱們用build()生成的Picasso 實例來加載圖片就會使用自定義的下載器來下載圖片了。
(3) 配置緩存
前面說過,內存緩存是用的LRU Cahce ,大小是手機內存的15% ,若是你想緩存大小更大一點或者更小一點,能夠自定義,而後配置。
上面只是一個簡單的舉例,固然了你能夠自定義,也可使用LRUCache,改變大小,改變存儲路徑等等。
提示: 很遺憾,好像沒有提供改變磁盤緩存的接口,那就只能用默認的了。
(4) 配置線程池
Picasso 默認的線程池的核心線程數爲3,若是你以爲不夠用的話,能夠配置本身須要的線程池,舉個列子:
(5) 配置全局的 Picasso Instance
上面說的這些自定義配置項目都是應用在一個局部的Picasso instance 上的,咱們不可能每一次使用都要從新配置一下,這樣就太麻煩了。咱們但願咱們的這些自定義配置能在整個項目都應用上,而且只配置一次。其實Picasso 給咱們提供了這樣的方法。能夠調用setSingletonInstance(Picasso picasso)
就能夠了,看一下這個方法的源碼:
設置一個經過with方法返回的全局instance。咱們只但願配置一次,因此,咱們應該在Application 的onCreate方法中作全局配置就能夠了。app一啓動就配置好,而後直接和前面的使用方法同樣,調用with方法獲取Picasso instance 加載圖片就OK了。
所以在Application 中添加以下代碼:
而後應用這些自定義配置加載圖片
用法和之前的同樣,可是咱們已經將咱們的自定義配置應用上了。
以上就是對Picasso 用法的所有總結,若有什麼問題,歡迎留言指正。Picasso真的是一個強大的圖片加載緩存庫,API 簡單好用,並且是鏈式調用的(這點我特別喜歡)。官方文檔寫的比較簡單,不少用法都要看源碼和註釋才知道。但願本文能給纔開始使用Picasso 的同窗一點幫助。
做者:依然範特稀西連接:https://www.jianshu.com/p/c68a3b9ca07a來源:簡書簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。