Android圖片載入庫Picasso原始碼分析

puff_pig發表於2016-01-13

圖片載入在Android開發中是非常重要,好的圖片載入庫也比比皆是。ImageLoader、PicassoGlideFresco均是優秀的圖片載入庫。

以上提到的幾種圖片載入庫各有特色。用法與比較,網上已經很多了。

出於學習的角度,個人認為從Picasso入手較好。程式碼量小,同時API優美,很適合我們學習。

今天筆者就Picasso的原始碼進行分析,丟擲一些圖片載入的技術細節供園友參考。

PS:建議園友先大致看一下原始碼。

我們對圖片載入的要求

1.載入速度要快

2.資源消耗要低

3.載入圖片不能錯位

Picasso是否滿足要求?

載入速度要快

1.標配策略,MemoryCache+DiskCache+Net。提高載入速度,同時保證流量。

2.Net部分,兼顧單請求載入速度與多請求併發能力,從而提高整體載入速度。

3.MemoryCache部分,通過Lru策略提高快取效率。

資源消耗要低

1.渲染適當尺寸圖片來減少記憶體。

2.通過執行緒池來限制併發的圖片載入執行緒,降低資源消耗。

3.請求相同圖片的執行緒要合併,減少執行緒數。

載入圖片不能錯位

AdapterView會 複用 View,Picasso通過Map<ImageView,Action>機制保證View展示正確的圖。

可見,Picasso已經滿足了我們對圖片載入的需求。

Picasso的一些基本策略

快取策略 MemoryCache+DiskCache+Net

1.MemoryCache採用的是Lru策略,持有一定數量處理過的圖(譬如經過resize/rotate處理,可直接設定到view中)。

2.DiskCache是網路圖片在本地的快取,快取的是原圖,可能需要經過處理才能設定到view中。

3.Net是圖片伺服器,當MemoryCache和DiskCache均取不到圖片時,網路拉取,成本最高。

圖片錯位

為了保證圖片不會錯位,Picasso維護了Map<ImageView,Action>,每個ImageView均只對應一個Action。

若獲取的圖片Action與ImageView不符合,則丟棄,等待正確的Action執行完。

效能

1.Picasso的執行緒池是優化過的,根據當前裝置網路狀況設定ThreadCount。

在網路良好的條件下,執行緒池持有較多執行緒,保證下載速度夠快。在網路較差的條件下(2G網路等),執行緒池減少持有執行緒,保證頻寬不會被多個連線阻塞。

2.Picasso將圖片uri、resize、transform等引數糅合為key,將key封裝到Action中進行請求。

請求執行緒Hunter對相同key的Action進行合併,請求完成後,Action依次得到圖片。

以上是Picasso的一些基本策略,可能看不太懂,接下來結合 Picasso載入ImageView圖片的場景 來串一下流程。

流程與原始碼分析

例項化

picasso的例項化有兩種方式

1.Picasso.with(context)

此方法提供預設方式,生成單例的Picasso物件。

2.new Picasso.Builder(context).build()

此方式提供自定義執行緒池、快取、下載器等方法。

獲取RequestCreator

picasso作為圖片載入庫,作用便是下載圖片。我們拿到picasso例項後,正常思路便是呼叫picasso.load()。

load()有四個方法,引數各不相同,不過可以分為兩類:uri和resourceId。uri又分為file和net。

load()的返回結果是RequestCreator物件,RequestCreator是用來配置載入引數的。

RequestCreator

RequestCreator有兩個功能

1.配置載入引數。

包括placeHolder與error圖片,載入圖片的大小、旋轉、居中等屬性。

2.執行載入。

通過呼叫into(object)方法進行載入。

into方法主流程梳理如下

Android圖片載入庫Picasso原始碼分析

後續的工作就交由Hunter來處理了

備註1:(imageview,action)是用來保證imageview與正確action匹配的。

備註2:hunterMap通過key持有多個hunter,同一個hunter可以對應多個action

Hunter

hunter是一個Runnable,作用是獲取圖片。

hunter的執行流程:在run()方法中執行hunt()方法嘗試獲取圖片,結果(成功、失敗、異常)交給Dispatcher回撥。

hunter的基礎類是BitmapHunter,但它卻是一個模版類,最重要的decode(request)方法交由子類來實現。

hunt()方法主流程梳理如下:

Android圖片載入庫Picasso原始碼分析

Dispatcher

Dispatcher是分發器,由Picasso或Hunter來呼叫。

Picasso或BitmapHunter只能呼叫dispatcher**()方法。

原因是不能確定是main執行緒或Hunter執行緒在呼叫,所以Dispatcher索性對所有的呼叫均經過Dispatcher轉發,轉發後呼叫perform**()方法,這樣即可保證在main執行緒中操作事件。

API如下:

dispatcherSubmit()和dispatcherCancel()

hunter中加入action便呼叫dispatcherSubmit(),hunter中取消action便呼叫dispatcherCancel()

dispatcherComplete()和dispatcherError()

載入結束時呼叫。均呼叫batch方法,不過complete操作會將bitmap加入到cache中,以便後續呼叫。

batch()

起緩衝作用,每隔0.2s執行一次performBatchComplete()批處理。批處理將hunterList回撥給Picasso,Picasso對每個hunter的每個action進行結果回撥。

其他

跟隨ImageView的圖片載入,應該對Picasso的原始碼已經有了一定了解。但是還有幾個相對獨立的模組沒有涉及到,園友們直接閱讀原始碼即可。

downloader提供了UrlConnection和OKHttp兩種方案,優先選用OKHttp。主要新增了httpCache。

Stats主要用於資料統計,很獨立的模組。

相關文章