老生常談了兑宇,但是還是有很多細節(jié)不知道的碍侦。先挖個坑,后面慢慢埋~
圖片加載框架隶糕?
- Picasso
- Glide
- Fresco
Picasso:
Picasso :和Square的網絡庫一起能發(fā)揮最大作用瓷产,因為Picasso可以選擇將網絡請求的緩存部分交給了okhttp實現。
Glide:模仿了Picasso的API枚驻,而且在他的基礎上加了很多的擴展(比如gif等支持)拦英,Glide默認的Bitmap格式是RGB_565,比 Picasso默認的ARGB_8888格式的內存開銷要小一半测秸;Picasso緩存的是全尺寸的(只緩存一種)疤估,而Glide緩存的是跟ImageView尺寸相同的(即56*56和128*128是兩個緩存) 。
FB的圖片加載框架Fresco:最大的優(yōu)勢在于5.0以下(最低2.3)的bitmap加載霎冯。在5.0以下系統(tǒng)铃拇,Fresco將圖片放到一個特別的內存區(qū)域(Ashmem區(qū))。當然沈撞,在圖片不顯示的時候慷荔,占用的內存會自動被釋放。這會使得APP更加流暢缠俺,減少因圖片內存占用而引發(fā)的OOM显晶。為什么說是5.0以下贷岸,因為在5.0以后系統(tǒng)默認就是存儲在Ashmem區(qū)了。
Fresco性能上的優(yōu)點
優(yōu)一:
1磷雇、支持webp格式的圖片偿警,是Google官方推行的,它的大小比其它格式圖片的大小要小一半左右唯笙,目前各個大公司都漸入的使用這種圖片格式了螟蒸,比如:Youtube、Gmail崩掘、淘寶七嫌、QQ空間等都已嘗鮮,使用該格式最大的優(yōu)點就是輕量苞慢、省流量诵原、圖片加載迅速。而Fresco是通過jni來實現支持WebP格式圖片挽放。
優(yōu)二:
2、5.0以下系統(tǒng):使用”ashmem”(匿名共享內存)區(qū)域存儲Bitmap緩存骂维,這樣Bitmap對象的創(chuàng)建、釋放將永遠不會觸發(fā)GC贺纲,關于”ashmem”存儲區(qū)域航闺,它是一個不在Java堆區(qū)的一片存儲內存空間,它的管理由Linux內核驅動管理猴誊,不必深究潦刃,只要知道這塊存儲區(qū)域是別于堆內存之外的一塊空間就行了,且這塊空間是可以多進程共享的懈叹,GC的活動不會影響到它乖杠。5.0以上系統(tǒng),由于內存管理的優(yōu)化澄成,所以對于5.0以上的系統(tǒng)Fresco將Bitmap緩存直接放到了堆內存中胧洒。
關于”ashmem”的存儲區(qū)域,我們的應用程序并不能像訪問堆內存一樣直接訪問這塊內存塊墨状,但是也有一些例外卫漫,對于Bitmap而言,有一種為”Purgeable Bitmap”可擦除的Bitmap位圖是存儲在這塊內存區(qū)域中的肾砂,BitmapFactory.Options中有這么一個屬性 inPurgeable :
BitmapFactory.Options = new BitmapFactory.Options();
options.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options);
所以通過配置inPurgeable = true這個屬性列赎,這樣解碼出來的Bitmap位圖就存儲在”ashmem”區(qū)域中,之后用到”ashmem”中得圖片時镐确,則把這個圖片從這個區(qū)域中取出來包吝,渲染完畢后則放回這個位置饼煞。
既然Fresco中Bitmap緩存在5.0以前是放在”ashmem”中,GC并不會回收它們诗越,且也不會被”ashmeme”內置的清除機制回收它們砖瞧,所以這樣雖然使得在堆中不會造成內存泄露,而在這塊區(qū)域可能造成內存泄露掺喻,Fresco中采取的辦法則是使用引用計數的方式芭届,其中有一個SharedReference這個類,這個類中有這么兩個方法:addReference()和deleteReference()感耙,通過這兩個基本方法來對引用進行計數褂乍,一旦計數為零時,則對應的資源將會清除(如:Bitmap.recycle()等)即硼,而Fresco為了考慮更容易被我們使用逃片,又提供了一個CloseableReference類,該類可以說是SharedReference類上功能的封裝只酥,CloseableReference同時也實現了Cloneable褥实、Closeable接口,它在調用.clone()方法時同時會調用addReference()來增加一個引用計數裂允,在調用.close()方法時同時會調用deleteReference()來刪除一個引用計數损离,所以在使用Fresco的使用,我們都是與CloseableReference類打交道绝编,使用CloseableReference必須遵循以下兩條規(guī)則:
1僻澎、在賦值CloseableReference給新對象的時候,調用.clone()進行賦值
2十饥、在超出作用域范圍的時候窟勃,必須調用.close(),通常會在finally代碼塊中調用
void gee() {
CloseableReference<Val> ref = foo();
try {
haa(ref);
} finally {
ref.close();
}
}
遵循這些規(guī)則可以有效地防止內存泄漏逗堵。
優(yōu)三:
3秉氧、使用了三級緩存:Bitmap緩存+未解碼圖片緩存+硬盤緩存。其中前兩個就是內存緩存蜒秤,Bitmap緩存根據系統(tǒng)版本不同放在了不同內存區(qū)域中汁咏,而未解碼圖片的緩存只在堆內存中,Fresco分了兩步做內存緩存作媚,這樣做有什么好處呢梆暖?第一個好處就如上的第二條,第二個好處是加快圖片的加載速度掂骏,Fresco的加載圖片的流程為:查找Bitmap緩存中是否存在轰驳,存在則直接返回Bitmap直接使用,不存在則查找未解碼圖片的緩存,如果存在則進行Decode成Bitmap然后直接使用并加入Bitmap緩存中级解,如果未解碼圖片緩存中查找不到冒黑,則進行硬盤緩存的檢查,如有勤哗,則進行IO抡爹、轉化、解碼等一系列操作芒划,最后成Bitmap供我們直接使用冬竟,并把未解碼(Encode)的圖片加入未解碼圖片緩存,把Bitmap加入Bitmap緩存中民逼,如硬盤緩存中沒有泵殴,則進行Network操作下載圖片,然后加入到各個緩存中拼苍。
既然Fresco使用了三級緩存笑诅,而有兩級是內存緩存,所以當我們的App在后臺時或者在內存低的情況下在onLowMemory()方法中疮鲫,我們應該手動清除應用的內存緩存吆你,我們可以使用下面的方式:
ImagePipeline imagePipeline = Fresco.getImagePipeline();
//清空內存緩存(包括Bitmap緩存和未解碼圖片的緩存)
imagePipeline.clearMemoryCaches();
//清空硬盤緩存,一般在設置界面供用戶手動清理
imagePipeline.clearDiskCaches();
//同時清理內存緩存和硬盤緩存
imagePipeline.clearCaches();
3.總結:
Picasso所能實現的功能俊犯,Glide都能做妇多,無非是所需的設置不同。但是Picasso體積比起Glide小太多如果項目中網絡請求本身用的就是okhttp或者retrofit(本質還是okhttp)燕侠,那么建議用Picasso者祖,體積會小很多(Square全家桶的干活)。Glide的好處是大型的圖片流贬循,比如gif咸包、Video桃序,如果你們是做美拍杖虾、愛拍這種視頻類應用,建議使用媒熊。
Fresco在5.0以下的內存優(yōu)化非常好奇适,代價就是體積也非常的大,按體積算Fresco>Glide>Picasso
不過在使用起來也有些不便(小建議:他只能用內置的一個ImageView來實現這些功能芦鳍,用起來比較麻煩嚷往,我們通常是根據Fresco自己改改,直接使用他的Bitmap層)
MemoryFile 可以用來測試共享內存