Glide是一個快速高效的Android圖片加載庫,注重於平滑的滾動提供了易用的API,高性能、可擴展的圖片解碼管道以及自動的資源池技術。這個庫被普遍運用在google的開源項目中,包括2014年的google I/O大會上發佈的官方app。可是你們有沒有發現當使用glide加載大的gif圖片,或者加載不少個gif的列表時會有明顯卡頓,CPU和內存佔用量很高。咱們知道glide優點是擁有一套圖片生命週期的維護,可是在加載gif的時候glide效率明顯比不過android-gif-drawable,緣由就是後者是在native層進行加載的,使用的是giflib庫。那咱們是否能夠保留兩者的優點,取長補短呢?今天做者給你們分享一下如何對glide進行優化,但願能給你們帶來幫助。java
今天咱們分別用優化前和優化後的glide框架來加載gif圖片,而後使用profile來查看CPU和內存佔用狀況,而且進行一個對比。對比結果以下圖,CPU和內存佔用明顯下降。android
優化前:app
優化後:框架
如何進行優化?ide
想要進行優化,咱們就必須分析glide加載gif卡頓的緣由。glide加載gif是經過java層來加載,因此性能確定是要大打折扣。這裏咱們能夠想辦法將gif加載的過程放到native中,因而咱們想到了giflib。可是giflib是C庫,使用起來很是不方便,因而谷歌就封裝好giflib,提供了使用java就能夠調用到的API,這就是frameSequence。性能
步驟一:生成so文件優化
首先下載好framesequence和giflib包,而後在framesequence目錄中建立external目錄,並將giflib解碼目錄複製到該目錄下,而後執行ndk-build,最後將生成的so放到jnilibs目錄下。ui
步驟二:建立FrameSequence對象以及FrameSequenceDrawable對象google
frameSequence的sample項目中已有了,直接複製過來就可使用了
code
步驟三 自定義glide資源解碼器
通過以上三步,準備工做已作好,接下來就是要將frameSequence和glide進行結合了。frameSequence負責圖片解碼,glide負責下載和生命週期維護。想要替換解碼部分,就必須瞭解glide的實現了。glide加載過程分爲加載和解碼兩大步驟,其中加載過程是經過模型加載器(ModelLoader)來實現,而解碼過程是經過資源解碼器(ResourceDecoder)來實現的,因此咱們要作的就是將glide的ResourceDecoder中默認的解碼操做替換成frameSequence。
那應該怎麼給glide註冊一個資源解碼器呢?
其實Glide v4 使用 APT(註解處理器) 來生成出一個 API。能夠爲 Generated API 擴展自定義選項,咱們能夠繼承AppGlideModule,重寫registerComponents方法,在裏面添加一個gif解碼器。注意須要使用@GlideModule進行註解,添加完該註解後在編譯時會自動生成一些類。這裏將glide.getBitmapPool傳遞到解碼器中是爲了bitmap的複用
寫好這個類後,咱們直接編譯一下項目,就會發現glide自動爲咱們生成了不少的java文件,以下圖:
接下來咱們再看看核心的解碼器須要作什麼操做
咱們能夠看到,這裏面首先構造方法接收到了glide註冊機傳過來的bitmapPool,用在decode方法中進行復用。在handles中返回true表明咱們的解碼器直接處理了該任務,而後在最核心的decode方法中,咱們初始化了一個FrameSequenceDrawable而且返回。這裏因爲返回值是Resource,因此咱們不得不包了一層自定義的Resource子類。
什麼是內存抖動?
內存抖動是指頻繁的申請內存,而後又回收內存,使得內存使用很不穩定,萬一沒有回收好就會產生內存泄漏。
什麼是內存碎片?
在連續的內存空間中,有一部份內存被使用,另外一部分已經被回收,因此致使目前可以使用的內存空間不是連續的,而不是連續的將不能夠同時一次性拿來使用。好比內存空間是1 2 3 4個格子,其中1和3是正在使用的內存,2和4是空閒內存,此時若是2和4單個的內存空間不夠,那麼就須要同時申請到2和4,因爲2和4的空間不連續,因此就會致使申請失敗。其中2和4這2個內存空間就被稱爲內存碎片,過小的碎片將沒法使用,很是影響效率。
有關bitmapPool的複用
這裏我貼出谷歌官方的2張圖,第一張是複用前,每一個圖片都分配一個內存空間。第二張是複用後,全部圖片複用同一個bitmap空間,減小內存使用。
步驟四 自定義解碼器的使用
最後,咱們經過調用以前經過APT生成的GlideApp,而後經過as方法傳入FSDrawable的方式來調用咱們自定義的解碼器
是否還能優化一下調用流程?
以上實際的加載優化已經完成,可是咱們發現調用的時候須要as方法傳入FrameSequenceDrawable,寫起來很不方便,但願能改爲相似於asgif這種調用方法,這個又須要使用到glide自帶的APT技術了,換句話說咱們須要使用一個註解。這裏咱們新建一個類,類名隨意,而後使用一下@GlideExtension註解,這裏須要注意的是,類中必需要有一個私有無參構造方法,否則glide是會報錯的。而後咱們自定義一個asGif2方法,使用@GlideType進行標註,在裏面就調用requestBuilder.apply方法就行了。寫完之後要編譯一下,讓glide經過註解生成該方法,這樣就能夠直接調用了。
總結:glide優化其實就是指利用glide能夠自定義解碼器的特色,咱們本身來定義而且註冊了一個資源解碼器,其中指定使用FrameSequence來進行解碼,核心其實就是使用的giflib庫。利用native層來實現資源的解碼,提高了加載效率,其中咱們還特地對bitmap進行了複用。而後爲了調用方便,咱們將調用方式從as改成asGif2,調用更加清晰明瞭。