demo位址:https://github.com/596785154/ImageLoaderDemo
1. Android應用加載網絡圖檔
1.1 Android應用擷取網絡資源注意事項
- 需要添加通路網絡權限
- 現在Android不允許在主線程中操作網絡相關東西,是以和網絡操作相關的代碼要放在子線程中執行。
1.2 URL通路網絡資源
- 建立url對象,根據url找到圖檔位址
- 打開url對應的資源輸入流
- 從InputStream中解析出圖檔bitmap
- UI元件顯示圖檔
1.3 URLConnection通路網絡資源
借助于URLConnection類應用程式可以非常友善的與指定站點交換資訊:包括發送GET請求、POST請求,并擷取網站的響應。
- 建立url對象,根據url找到圖檔位址
- 通過url對象openConnection方法建立URLConnection對象
- 設定URLConnection的參數和普通請求屬性
- 如果隻是發送GET方式請求,使用connect方法建立和遠端資源之間的實際連接配接即可,(如果發送POST方式的請求,需要擷取URLConnection執行個體對應的輸出流來發送請求。)
- 遠端資源變為可用,程式輸入流讀取遠端資源的資料。
- 從InputStream中解析出圖檔bitmap
- UI元件顯示圖檔
1.4 HttpURLConnection通路網絡資源
HttpURLConnection是URLConnection子類。通路方式和URLConnection一樣。
- 建立url對象,根據url找到圖檔位址
- 通過url對象openConnection方法建立HttpURLConnection對象
- 設定HttpURLConnection的參數和普通請求屬性
- 如果隻是發送GET方式請求,使用connect方法建立和遠端資源之間的實際連接配接即可,(如果發送POST方式的請求,需要擷取URLConnection執行個體對應的輸出流來發送請求。)
- 遠端資源變為可用,程式輸入流讀取遠端資源的資料。
- 從InputStream中解析出圖檔bitmap
- UI元件顯示圖檔
1.5 HttpClient通路(未經驗證)
HttpClient是增強版HttpURLConnection。可以通路被保護的網站:需要使用者登入和使用者權限的網站。
- 建立HttpClient對象
- 建立HttpGet/HttpPost對象
- 設定請求參數
- 調用HttpClient對象的execute(HttpUriRequest request request)發送請求,執行該方法傳回一個HttpResponse.
- 調用HttpResponse的getEntity()方法擷取HttpEntity對象。
- 調用HttpEntity的getContent()方法擷取到輸入流内容
- 從InputStream中解析出圖檔bitmap
- UI元件顯示圖檔
1.6 WebView浏覽
WebView本身是一個浏覽器實作,核心基于開源WebKit引擎。
注意:有一點問題,就是第一次加載時,如果圖檔沒擷取到會出現錯誤的圖檔
- 在布局檔案中添加WebView控件
- 使用WebView自身的loadUrl(String url)方法通過url加載圖檔
2. 使用開源庫加載圖檔
2.1 開源庫的優點
-
使用簡單
都可以通過一句代碼可實作圖檔擷取和顯示。
-
可配置度高,自适應程度高
圖檔緩存的下載下傳器(重試機制)、解碼器、顯示器、處理器、記憶體緩存、本地緩存、線程池、緩存算法等大都可輕松配置。
自适應程度高,根據系統性能初始化緩存配置、系統資訊變更後動态調整政策。比如根據 CPU 核數确定最大并發數,根據可用記憶體确定記憶體緩存大小,網絡狀态變化時調整最大并發數等
-
多級緩存
都至少有兩級緩存、提高圖檔加載速度。
-
支援多種資料源
支援多種資料源,網絡、本地、資源、Assets 等
-
支援多種 Displayer
不僅僅支援 ImageView,同時支援其他 View 以及虛拟的 Displayer 概念。
-
其他小共同點
包括支援動畫、支援 transform 處理、擷取 EXIF 資訊等。
2.2 ImageLoader
2.2.1 設計及流程
整個庫分為 ImageLoaderEngine,Cache 及 ImageDownloader,ImageDecoder,BitmapDisplayer,BitmapProcessor 五大子產品,其中 Cache 分為 MemoryCache 和 DiskCache 兩部分。
ImageLoader 收到加載及顯示圖檔的任務,并将它交給 ImageLoaderEngine,ImageLoaderEngine 分發任務到具體線程池去執行,任務通過 Cache 及 ImageDownloader 擷取圖檔,中間可能經過 BitmapProcessor 和 ImageDecoder 處理,最終轉換為Bitmap 交給 BitmapDisplayer 在 ImageAware 中顯示。

2.2.2 功能特性
- 多線程異步加載和顯示圖檔(圖檔來源于網絡、sd卡、assets檔案夾,drawable檔案夾(不能加載9patch),新增加載視訊縮略圖)
- 支援通過“listener”監視加載的過程,可以暫停加載圖檔,在經常使用的ListView、GridView中,可以設定滑動時暫停加載,停止滑動時加載圖檔(便于節約流量,在一些優化中可以使用)
- 緩存圖檔至記憶體時,可以更加高效的工作
- 高度可定制化(可以根據自己的需求進行各種配置,如:線程池,圖檔下載下傳器,記憶體緩存政策等)
- 支援圖檔的記憶體緩存,SD卡(檔案)緩存
- 在網絡速度較慢時,還可以對圖檔進行加載并設定下載下傳監聽
2.2.3 使用步驟
- 添加jar包
- Manifest.xml檔案中添加網絡和讀寫SD卡權限
- 在Application中配置ImageLoaderConfiguration參數,配置好ImageLoaderConfiguration,一定不要忘記進行初始化操作
- 首先要得到ImageLoader的執行個體(使用的單例模式)
- 相關顯示參數配置
- 顯示圖檔
2.3 Picasso
2.3.1 設計及流程
整個庫分為 Dispatcher,RequestHandler 及 Downloader,PicassoDrawable 等子產品。
Picasso 收到加載及顯示圖檔的任務,建立 Request 并将它交給 Dispatcher,Dispatcher 分發任務到具體 RequestHandler,任務通過 MemoryCache 及 Handler(資料擷取接口) 擷取圖檔,圖檔擷取成功後通過 PicassoDrawable 顯示到 Target 中。
2.3.2 功能特性
1.自帶統計監控功能
支援圖檔緩存使用的監控,包括緩存命中率、已使用記憶體大小、節省的流量等。
2.支援優先級處理
每次任務排程前會選擇優先級高的任務,比如 App 頁面中 Banner 的優先級高于 Icon 時就很适用。
3.支援延遲到圖檔尺寸計算完成加載
4.支援飛行模式、并發線程數根據網絡類型而變
手機切換到飛行模式或網絡類型變換時會自動調整線程池最大并發數,比如 wifi 最大并發為 4, 4g 為 3,3g 為 2。(Picasso 根據網絡類型來決定最大并發數,而不是 CPU 核數。)
5.無”本地緩存
“無”本地緩存,不是說沒有本地緩存,而是 Picasso 自己沒有實作,交給了 Square 的另外一個網絡庫 okhttp 去實作,這樣的好處是可以通過請求 Response Header 中的 Cache-Control 及 Expired 控制圖檔的過期時間。
2.3.3 使用步驟
- 添加jar包
- Manifest.xml檔案中添加網絡和讀寫SD卡權限
- 配置并顯示圖檔
2.4 Glide
2.4.1 設計及流程
整個庫分為 RequestManager(請求管理器),Engine(資料擷取引擎)、Fetcher(資料擷取器)、MemoryCache(記憶體緩存)、DiskLRUCache、Transformation(圖檔處理)、Encoder(本地緩存存儲)、Registry(圖檔類型及解析器配置)、Target(目标)等子產品。
Glide 收到加載及顯示資源的任務,建立 Request 并将它交給RequestManager,Request 啟動 Engine 去資料源擷取資源(通過 Fetcher ),擷取到後 Transformation 處理後交給 Target。
Glide 依賴于 DiskLRUCache、GifDecoder 等開源庫去完成本地緩存和 Gif 圖檔解碼工作。
2.4.2 功能特性
1.圖檔緩存->媒體緩存
Glide 不僅是一個圖檔緩存,它支援 Gif、WebP、縮略圖。甚至是 Video,是以更該當做一個媒體緩存。
2.支援優先級處理
3.與 Activity/Fragment 生命周期一緻,支援 trimMemory
Glide 對每個 context 都保持一個 RequestManager,通過 FragmentTransaction 保持與 Activity/Fragment 生命周期一緻,并且有對應的 trimMemory 接口實作可供調用。
4.支援 okhttp、Volley
Glide 預設通過 UrlConnection 擷取資料,可以配合 okhttp 或是 Volley 使用。實際 ImageLoader、Picasso 也都支援 okhttp、Volley。
5.記憶體友好
(1)Glide 的記憶體緩存有個 active 的設計
從記憶體緩存中取資料時,不像一般的實作用 get,而是用 remove,再将這個緩存資料放到一個 value 為軟引用的 activeResources map 中,并計數引用數,在圖檔加載完成後進行判斷,如果引用計數為空則回收掉。
(2)記憶體緩存更小圖檔
Glide 以 url、viewwidth、viewheight、螢幕的分辨率等做為聯合 key,将處理後的圖檔緩存在記憶體緩存中,而不是原始圖檔以節省大小
(3)與 Activity/Fragment 生命周期一緻,支援 trimMemory
(4)圖檔預設使用預設 RGB565 而不是 ARGB888
雖然清晰度差些,但圖檔更小,也可配置到 ARGB_888。
(5)其他:Glide 可以通過 signature 或不使用本地緩存支援 url 過期
2.4.3 使用步驟
- 添加jar包
- Manifest.xml檔案中添加網絡和讀寫SD卡權限
- 配置并顯示圖檔
2.5 Fresco
2.5.1 設計及流程
核心類:
DraweeView(子類:SimpleDraweeView),DraweeHierarchy(子類:GenericDraweeHierarchy),DraweeController。(類似MVC)
DraweeView:
子類也是SimpleDraweeView,用于顯示在螢幕上的視圖,相當于V。
DraweeHierarchy:
子類是GenericDraweeHierarchy,主要用于維護和繪制Drawable對象,以及怎樣展示等等。相當于M。
DraweeController:
控制器,主要和ImageLoader互動,比如說為圖檔設定uri,能否在失敗時重新加載等等。相當于C。
Fresco的Image Pipeline
2.5.2 功能特性
1.記憶體管理
在5.0以下系統,Fresco将圖檔放到一個特别的記憶體區域。在圖檔不顯示的時候,占用的記憶體會自動被釋放。這會使得APP更加流暢,減少因圖檔記憶體占用而引發的OOM。
2.圖檔加載
Fresco的Image Pipeline允許使用者用很多種方式來自定義圖檔加載過程
• 為同一個圖檔指定不同的遠端路徑,或者使用已經存在本地緩存中的圖檔
• 先顯示一個低清晰度的圖檔,等高清圖下載下傳完之後再顯示高清圖
• 加載完成回調通知
• 對于本地圖,如有EXIF縮略圖,在大圖加載完成之前,可先顯示縮略圖
• 縮放或者旋轉圖檔
• 對已下載下傳的圖檔再次處理
• 支援WebP解碼,即使在早先對WebP支援不完善的Android系統上也能正常使用!
3.圖檔繪制
Fresco 的 Drawees 設計,帶來一些有用的特性:
• 自定義居中焦點
• 圓角圖,當然圓圈也行
• 下載下傳失敗之後,點選重制下載下傳
• 自定義占位圖,自定義overlay, 或者進度條
• 指定使用者按壓時的overlay
4.圖檔的漸進式呈現
漸進式圖檔格式先呈現大緻的圖檔輪廓,然後随着圖檔下載下傳的繼續,呈現逐漸清晰的圖檔,這對于移動裝置,尤其是慢網絡有極大的利好,可帶來更好的使用者體驗。
5.動圖加載
Fresco 支援 GIF 和 WebP 格式的動畫圖檔。
2.5.3 使用步驟
1.Manifest.xml檔案中添加網絡和讀寫SD卡權限
2.導入
dependencies {
compile 'com.facebook.fresco:fresco:0.8.0+'//添加的版本可根據官網上的版本
}
3.在project的build.gradle檔案中添加①代碼:
allprojects {
repositories {
jcenter()
mavenCentral()//①
}
}
4.在你的application類onCreate方法中添加并在manifest.xml檔案中添加Application的name屬性等于目前application類名
Fresco.initialize(instance);
5.在xml中引入SimpleDraweeView
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_view"
android:layout_width="100dp"
android:layout_height="150dp"
fresco:placeholderImage="@drawable/my_drawable"
/>
注意:在SimpleDraweeView的父控件或者根節點中配置
6.在Java代碼中開始加載圖檔
Uri uri = Uri.parse("http://content.52pk.com/files/100623/2230_102437_1_lit.jpg");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
draweeView.setImageURI(uri);
2.6 Volley
2.6.1 設計及流程
主要是通過兩種Diapatch Thread不斷從RequestQueue中取出請求,根據是否已緩存調用Cache或Network這兩類資料擷取接口之一,從記憶體緩存或是伺服器取得請求的資料,然後交由ResponseDelivery去做結果分發及回調處理。
主線程中調用RequestQueue的add()方法來添加一條網絡請求,這條請求會先被加入到緩存隊列當中,如果發現可以找到相應的緩存結果就直接讀取緩存并解析,然後回調給主線程。如果在緩存中沒有找到結果,則将這條請求加入到網絡請求隊列中,然後處理發送HTTP請求,解析響應結果,寫入緩存,并回調主線程。
2.6.2 功能特性
- 通信更快,更簡單,更健壯
- Get、Post網絡請求及網絡圖像的高效率異步處理請求
- 對網絡請求進行排序優先級處理
- 網絡請求的緩存
- 多級别取消請求(同時取消正在進行的多個網絡請求)
- 和Activity生命周期的關聯(當Activity銷毀的時候可以同時取消正在進行的網絡請求操作,提高性能)
2.6.3 使用步驟
使用imageRequest加載圖檔:
1)建立一個RequestQueue對象。
2)建立一個Request對象。
3)将Request對象添加到RequestQueue裡面。
使用imageLoader加載圖檔:
1)建立一個RequestQueue對象。
2)建立一個ImageLoader對象。
3)擷取一個ImageListener對象。
4)調用ImageLoader的get()方法加載網絡上的圖檔。
使用NetworkImageView加載圖檔:
1)建立一個RequestQueue對象。
2)建立一個ImageLoader對象。
3)在布局檔案中添加一個NetworkImageView控件。
4)在代碼中擷取該控件的執行個體。
5)設定要加載的圖檔位址
2.7 幾種開源庫的差別
- fresco是重量級庫,适合大型應用不适合小應用。ImageLoader、Glide、picasso是輕量級圖檔架構适合小型應用。Volley适合網絡通信操作頻繁但資料量小的操作,不适合大資料量的網絡操作。
- glide和picasso使用大緻相同,但glide可以加載動态圖但picasso做不到,glide可以接收Activity/Fragment作為with的參數用以将生命周期和activity/fragment生命周期保持一緻而picasso不能。
- Volley不能加載本地圖檔,其他幾種架構均可以。并且不支援上傳和下載下傳。
- Volley可以定制自己的Request