本篇文章已授權(quán)微信公眾號 guolin_blog (郭霖)獨家發(fā)布
- 本文章所使用的 Glide 源碼版本:4.11.0
上一篇:Glide 三部曲之圖片加載流程
開胃菜
- 在講之前,我們先補充一點基礎(chǔ)知識,安卓 ImageView 支不支持加載 Gif 動圖呢?其實是不支持的,因為 ImageView 本身就是一個 View,View 的繪制需要用 Canvas,而 Canvas 只支持 canvas.drawBitmap,也就是同一時間只能繪制一張位圖,而 Gif 是由多幀圖片組成,那么 Glide 是如何讓 ImageView 實現(xiàn)播放 Gif 動圖呢?

- 還是從 Glide 給我們提供的寫法來入手這塊的源碼

- 一上來就發(fā)現(xiàn)了今天的主角:GifDrawable

- 確認過眼神,是想要的類

- 那么問題來了,這個類有將近 500 多行代碼,我們該從哪里看起?

- 這就跟看書類似,我們可以先看目錄,在源碼中也差不多,只不過它叫代碼結(jié)構(gòu)
源碼解析
- 通過查看代碼結(jié)構(gòu),我們發(fā)現(xiàn)了一個方法,從方法名上理解,它是開始播放第一幀的方法,那么我們就從這個方法入手

- 我們可以看到當 Gif 只有一幀的時候,會直接調(diào)用繪制方法,而 Gif 不止一幀的時候,那么它就開啟了訂閱,接下來讓我們看看這個訂閱的方法里面做了什么事情



- 接下來讓我們重點看一下這三句代碼分別做了什么事


- 看到這里我們大概明白了,這個方法是用來遞增幀位置的,從它的算法來看,這還是一個無限輪播的算法

- 看完了 advance 的作用,我們回去接著看剩下的兩句代碼

- 是不是忽然有點蒙,這個類是什么,我們先看一下它的父類

- 是不是有點似曾相識,但就是怎么也說不出來什么,讓我們先看看它的父類

這個 Target 就是我們上篇講到圖片加載流程提到過的接口
這個接口的作用就是回調(diào)一些加載監(jiān)聽,這個接口前面三個方法分別是:加載開始、加載失敗、加載成功讀取資源的回調(diào)

- 現(xiàn)在我們知道了這個是加載資源的回調(diào),那么它又是從哪里調(diào)用的?

- 就是在我們后面要講的第三句代碼里面調(diào)用的,真是讓人意想不到

- 我們看到在加載資源的回調(diào)中發(fā)送了一個消息,那么這個消息最終是去了哪里,接下來讓我們根據(jù)這個消息的 what 參數(shù)進行跟蹤

- 看到 handleMessage 忽然有了一種熟悉的味道,我們看到這里主要處理了兩種消息,一種是延遲消息,一種是清理消息。接下來讓我們先看看,如果這是一個延遲消息會發(fā)生什么事




- 在這里我們看到,它會先獲取當前幀數(shù)據(jù),然后再通過 Canvas.drawBitmap 到 ImageView 上面,接下來我們回去剛剛那個方法里面,看看它還做了些什么


原來如此,它在刷新新的一幀數(shù)據(jù)到 ImageView 之后,會對舊的一幀數(shù)據(jù)進行清除
然后再回去繼續(xù)看,它還做了什么事


- 還是原來的方法,還是熟悉的三句代碼
總結(jié)
- Glide 加載 Gif 的原理比較簡單,就是將 Gif 解碼成多張圖片進行無限輪播,每幀切換都是一次圖片加載請求,再加載到新的一幀數(shù)據(jù)之后會對舊的一幀數(shù)據(jù)進行清除,然后再繼續(xù)下一幀數(shù)據(jù)的加載請求,以此類推,使用 Handler 發(fā)送消息實現(xiàn)循環(huán)播放。