編輯:Android資訊
在Android開發中,ImageLoader應該算得上是最重要的開源庫之一,由於項目原因(不能使用開源庫),前段時間自己也是需要實現一個簡單的ImageLoader,因此誕生了這個庫,我們暫且叫它為SimpleImageLoader。就目前而言,你上網查ImageLoader資料的時候,基本上能夠找到很簡單的實現,基本上一個類就把所有的工作給做了,這就顯得很不專業了嘛,很多時候我們不只是需要實現功能,而是希望能夠在實現功能的同時在設計層面有所提升。
SimpleImageLoader分享出來的主要目的並不是說替代那些著名開源庫,而是提供一個簡單的、又有一定參考價值的ImageLoader實現讓一些需要幫助的人學習,在深入了解實現的同時學到知識,也能夠體會到在設計一個開源庫時應該要做哪些考慮、做哪些取捨、有什麼模式,當然在了解了ImageLoader的實現之後再去使用專業的開源庫也會更加的得心應手,出現問題的時候自己也能夠不太費力地去究其原因。在提升自己的同時也能夠了解一些開源庫的設計基本原則,這也是我的博客中一直主張的觀點。
當然限於本人水平有限,有bug在所難免,但是我們這裡是以學習為目的,了解ImageLoader的設計與實現才是我們最重要的目的,一些細節不必在意,可以在你深入的學習過程中修改你認為不合理或者錯誤的地方。如果你有好的實現方法或者有好的建議,也都請指教一二;如果你認為我寫的東西爛得不值一提,那你就深深地埋藏在心裡吧。
圖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卡的另一個目錄中。這樣,整個加載過程也就完成了。
上述效果中有四張圖片是顯示不出來的,因為在圖片uri列表中有三張是我手機中的圖片,模擬器中沒有,因此顯示加載失敗。還有一張是無效的uri,也是加載失敗。
Github倉庫地址將在下一篇博客中給出,敬請期待!!
SQLite是Android平台軟件開發中會經常用到的數據庫產品,作為一款輕型數據庫,SQLite的設計目標就是是嵌入式的,而且目前已經在很多嵌入式產品中使用了它
Volley下載 Google I/O 2013 大會上發布的 Android 異步網絡請求框架和圖片加載框架。 試用場景:適合數據量小,通信頻繁的網絡操作。 g
本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃! 隨著Android平台持續驚人的增長,越來越多的開發人員開始工作於
1. 簡介 直到4g時代,流量依然是寶貴的東西。而移動網絡傳輸中,最占流量的一種載體:圖片,成為了我們移動開發者不得不關注的一個問題。 我們關注的問題,無非是圖片