教你寫Android ImageLoader架構之基本架構

來源:互聯網
上載者:User

標籤:android   imageloader   架構   圖片載入   

前言

在Android開發中,ImageLoader應該算得上是最重要的開源庫之一,由於項目原因(不能使用開源庫),前段時間自己也是需要實現一個簡單的ImageLoader,因此誕生了這個庫,我們暫且叫它為SimpleImageLoader。就目前而言,你上網查ImageLoader資料的時候,基本上能夠找到很簡單的實現,基本上一個類就把所有的工作給做了,這就顯得很不專業了嘛,很多時候我們不只是需要實現功能,而是希望能夠在實現功能的同時在設計層面有所提升。

SimpleImageLoader分享出來的主要目的並不是說替代那些著名開源庫,而是提供一個簡單的、又有一定參考價值的ImageLoader實現讓一些需要協助的人學習,在深入瞭解實現的同時學到知識,也能夠體會到在設計一個開源庫時應該要做哪些考慮、做哪些取捨、有什麼模式,當然在瞭解了ImageLoader的實現之後再去使用專業的開源庫也會更加的得心應手,出現問題的時候自己也能夠不太費力地去究其原因。在提升自己的同時也能夠瞭解一些開源庫的設計基本原則,這也是我的部落格中一直主張的觀點。

當然限於本人水平有限,有bug在所難免,但是我們這裡是以學習為目的,瞭解ImageLoader的設計與實現才是我們最重要的目的,一些細節不必在意,可以在你深入的學習過程中修改你認為不合理或者錯誤的地方。如果你有好的實現方法或者有好的建議,也都請指教一二;如果你認為我寫的東西爛得不值一提,那你就深深地埋藏在心裡吧。


基本架構      一般來說,ImageLoader的實現都是基於線程池,在第一版的我也是使用線程池來載入圖片,但是後面的版本卻換成了跟SimpleNet類似的架構模式,原因是覺得線程池剛啟動的時候會稍微慢一些,我感覺不太爽就換了執行緒模式。當然我也會把線程池的版本在另外的分支上給出,這樣給一些需要的朋友參考。SimpleImageLoader的基本結構1所示。

圖1

看到這幅圖看過SimpleNet網路架構的朋友應該是會熟悉一些,基本結構與SimpleNet很相似,其實主要也是我們比較喜歡把架構圖畫成這種分層樣式,感覺比較好理解,

SimpleImageLoader類是使用者的入口,使用者在通過配置類初始化SimpleImageLoader之後就可以向SimpleImageLoader提交載入圖片的請求了。SimpleImageLoader內部維護了一個請求隊列,使用者提交的載入圖片的請求會在內部被封裝成BitmapRequest對象,然後將這些對象放到請求隊列中。在建立隊列時會建立使用者指定數量(預設為CPU個數 + 1)的線程來載入圖片,這些線程在內部命名為RequestDispatcher,它們在run函數中不斷地擷取隊列中的載入請求,然後交給對應的Loader載入圖片。

為了方便使用者的擴充,我們引入了Loader這個抽象,因為在SimpleImageLoader中只支援兩種圖片uri的載入,即網狀圖片uri和本地檔案的uri。網狀圖片一般以"http://"或者"https://"開頭,而本地圖片的uri格式卻是"file://"開頭,SimpleImageLoader內部通過圖片uri的格式的不同使用不同的Loader來載入圖片,這樣後續使用者就可以註冊Loader來實現其他格式的載入,例如"drawable:// + 圖片名"來載入res/drawable中的圖片等。這樣保證了SimpleImageLoader可載入圖片uri格式的可擴充性。Loader會通過LoaderManager來進行管理,如果需要註冊自己的Loader實現,則調用LoaderManager的register函數即可。如果你傳遞進去的圖片uri是無效,例如格式錯誤,那麼LoaderManager會返回一個預設的Loader,這個預設的Loader名為NullLoader,它其實什麼也不做,只是為了防止在外部進行判空而已,這種模式成為Null Object設計模式。當然,在載入圖片之前我們會從緩衝中讀取,如果有緩衝我們則不載入。

Loader載入完圖片之後會先更新UI,即將圖片顯示到對應的ImageView上,在構造BitmapRequest時內部已經將圖片的uri設定為ImageView的tag了。圖片載入完成後判斷ImageView的tag和uri是否相等,如果相等則將圖片顯示到ImageView上,否則不更新ImageView。這一步很重要,很多朋友在使用ImageLoader時出現問題基本上就是由於沒有設定ImageView的tag。

載入圖片的先後順序是由載入策略決定的,策略相關的內容沒有在架構圖中給出。載入策略決定了請求在隊列中的排序,在將請求添加到隊列中時會給每個請求設定一個序號,隊列將根據這個序號對請求進行排序。這樣我們就可以知道哪個請求是先添加進來的,也可以很方便的實現自己的策略類來定製自己的載入策略,比如最後載入到隊列中的請求最先載入。比如我們在ListView滾動時,最後添加到隊列中的圖片請求應該是我們最急需顯示的,我們它們就在手機的當前螢幕,而前面的請求對應的ImageView已經被複用,即使它們載入完成它們也不會被顯示,因為ImageView的tag已經變化了。因此,策略的靈活性依然很重要。

在載入完圖片並且更新UI之後,我們會將圖片緩衝起來。內建的緩衝類型有四種,無緩衝、記憶體緩衝、sd卡緩衝、記憶體和sd卡的雙緩衝,這四種緩衝都實現了Cache介面,如果你這四種緩衝類型還不能滿足你的需求,那麼你可以實現Cache介面,然後實現自己的緩衝邏輯,然後在配置ImageLoader時設定需要的緩衝類型(具體配置後續說明),如果不配置則預設使用的是記憶體緩衝。這裡我們又看到了一個面向介面編程的例子,即SimpleImageLoader只依賴於Cache介面的抽象,而不是說依賴於某個具體的緩衝類,這樣使用者就可以很方面的實現自己的緩衝邏輯,並且將緩衝實現注入到sdk中。當然,上述的Loader、載入策略實現也是基於同樣的理論基礎,就是說過很多遍的“面向介面編程”。

恩,是時候捋一捋這個執行流程了。

使用者調用displayImage請求載入圖片,SimpleImageLoader將這個載入圖片請求封裝成一個Request,然後加入到隊列中。幾個色眯眯的調度子線程不斷地從隊列中擷取請求,然後根據uri的格式擷取到對應的Loader來載入圖片。在載入圖片之前首先會查看緩衝中是否含有靶心圖表片(具體細節在後續的部落格再細說),如果有緩衝則使用緩衝,否則載入靶心圖表片。擷取到圖片之後,我們會將圖片投遞給ImageView進行更新,如果該ImageView的tag與圖片的uri是一樣的,那麼則更新ImageView,否則不處理。使用ImageView的tag與圖片的uri進行對比是為了防止圖片錯位顯示的問題,這在ImageLoader中是很重要的一步。如果靶心圖表片沒有緩衝,第一次從uri中載入後會加入緩衝中,當然從sdcard中載入的圖片我們只會緩衝到記憶體中,而不會再緩衝一份到sd卡的另一個目錄中。這樣,整個載入過程也就完成了。


SimpleImageLoader工程結構圖

           



上述效果中有四張圖片是顯示不出來的,因為在圖片uri列表中有三張是我手機中的圖片,模擬器中沒有,因此顯示載入失敗。還有一張是無效的uri,也是載入失敗。

Github倉庫地址將在下一篇部落格中給出,敬請期待!!


教你寫Android ImageLoader架構之基本架構

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.