Android Fresco圖片加載優(yōu)化的方案
優(yōu)化背景
一般情況下,F(xiàn)resco圖片加載需使用SimpleDraweeView,這個(gè)控件并不能自動(dòng)根據(jù)自身的尺寸按需加載圖片,即一個(gè) N×N 的UI控件,背后加載的實(shí)際圖片可能是 2N×2N。這就導(dǎo)致了實(shí)際應(yīng)用運(yùn)行過(guò)程中的內(nèi)存使用效率不高,需要針對(duì)其進(jìn)行內(nèi)存優(yōu)化。

在一些入門級(jí)硬件設(shè)備上,表現(xiàn)得尤為明顯,隨著程序的運(yùn)行時(shí)間的增長(zhǎng),OOM的風(fēng)險(xiǎn)也不斷加大。
Fresco版本:1.13.0
數(shù)據(jù)記錄
聲明控件大小為 480×270
<com.facebook.drawee.view.SimpleDraweeView android:id="@+id/simple_drawee_view" android:layout_width="480dp" android:layout_height="270dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" />
加載圖片代碼,調(diào)用Fresco的setImageURI
val mImageUrl = "https://static.runoob.com/images/demo/demo4.jpg" val simple_drawee_view = findViewById<SimpleDraweeView>(R.id.simple_drawee_view) simple_drawee_view.setImageURI(mImageUrl)
運(yùn)行后dump內(nèi)存如下,可以發(fā)現(xiàn)內(nèi)存中的圖片尺寸為1920×1080,即此時(shí)SimpleDraweeView會(huì)按照網(wǎng)絡(luò)上的原圖尺寸進(jìn)行加載,內(nèi)存占用大小為 8294475Bytes = 7.91Mb。一張圖片占用近8Mb,在圖片顯示十分豐富的頁(yè)面場(chǎng)景中,圖片總內(nèi)存占用大小將特別美麗,萬(wàn)一這個(gè)頁(yè)面又內(nèi)存泄漏了,那就更美麗了。

如果只加載 480×270 大小的圖片,內(nèi)存占用為 518475Bytes = 0.49Mb。相較于原來(lái) 1920×1080 尺寸,內(nèi)存減小了 94%!

優(yōu)化方案
Fresco提供了resize api,使得調(diào)用者在圖片解碼前可以修改內(nèi)存中圖片的大小,api大致如下
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri) .setResizeOptions(new ResizeOptions(width, height)) .build(); PipelineDraweeController controller = Fresco.newDraweeControllerBuilder() .setOldController(mDraweeView.getController()) .setImageRequest(request) .build(); mSimpleDraweeView.setController(controller);
注意這個(gè)方案在低版本中默認(rèn)只支持jpg圖片,如需支持其它圖片格式,需在設(shè)置image pipeline時(shí)添加isDownSample配置。同時(shí)對(duì)于產(chǎn)生的圖片的尺寸,只能粗略地控制,圖片不能修改為確定的尺寸。
.setDownsampleEnabled(true)
這個(gè)方案有個(gè)顯著的缺點(diǎn),那就是頁(yè)面適配性極差,需要配合View層的生命周期在確保能夠動(dòng)態(tài)獲取到控件寬高的時(shí)機(jī)進(jìn)行調(diào)用,對(duì)于一個(gè)成熟的項(xiàng)目工程,代碼改動(dòng)量過(guò)大,優(yōu)化成本過(guò)高。 這里采用編寫SimpleDraweeView的子類進(jìn)行優(yōu)化,利用向上轉(zhuǎn)型,盡可能的減小View層代碼的改動(dòng),只需要修改xml布局文件中的控件聲明即可。 方案架構(gòu)圖如下:

其中DesiredSimpleDraweeView為SimpleDraweeView的子類,在onWindowFocusChanged方法回調(diào)中可以明確獲知控件的具體寬高,之后再進(jìn)行圖片加載操作。
public class DesiredSimpleDraweeView extends SimpleDraweeView {
Uri mUri;
Object mCallerContext;
public DesiredSimpleDraweeView(Context context) {
super(context);
}
@Override
public void setImageURI(Uri uri, Object callerContext) {
mUri = uri;
mCallerContext = callerContext;
}
private void setImageURI(int width, int height) {
try {
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
.setResizeOptions(new ResizeOptions(width, height))
.build();
DraweeController controller =
getControllerBuilder()
.setOldController(getController())
.setImageRequest(imageRequest)
.build();
setController(controller);
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
setImageURI(getWidth(), getHeight());
}
}
}
復(fù)寫setImageURI(Uri,Object)方法,暫存uri和callerContext,在onWindowFoucusChanged回調(diào)之后再根據(jù)控件寬高進(jìn)行圖片的加載。 這樣,利用向上轉(zhuǎn)型,View層的代碼無(wú)需改動(dòng),xml文件中替換控件聲明后即可顯著提高內(nèi)存利用率。
注意事項(xiàng)
性能優(yōu)化是條永無(wú)止境的道路,沒(méi)有最牛的方案,只有最合適的方案。如果對(duì)于圖片加載尺寸想要精確控制,按需加載,Glide或許是更好的選擇。
以上就是Android Fresco圖片加載優(yōu)化的方案的詳細(xì)內(nèi)容,更多關(guān)于Android Fresco圖片加載優(yōu)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android利用ContentResolver訪問(wèn)者獲取手機(jī)短信信息
本篇文章主要介紹了android利用ContentResolver訪問(wèn)者獲取手機(jī)短信信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
Android使用AlarmManager設(shè)置鬧鐘功能
這篇文章主要為大家詳細(xì)介紹了Android使用AlarmManager設(shè)置鬧鐘功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09
Android使用ContentProvider初始化SDK庫(kù)方案小結(jié)
這篇文章主要介紹了Android使用ContentProvider初始化SDK庫(kù)方案總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
Android ViewPager的MVP架構(gòu)搭建過(guò)程
本文主要介紹了ViewPager在Android中的作用以及使用場(chǎng)景,如引導(dǎo)頁(yè)、圖片瀏覽器、新聞或文章內(nèi)容的多標(biāo)簽頁(yè)等,同時(shí),還詳細(xì)闡述了如何通過(guò)MVP架構(gòu)來(lái)搭建ViewPager,將視圖和邏輯進(jìn)行解耦,提高代碼的可測(cè)試性、可復(fù)用性,使代碼結(jié)構(gòu)更清晰且易于擴(kuò)展功能2024-10-10
安卓監(jiān)聽屏幕的橫豎翻轉(zhuǎn)實(shí)現(xiàn)方法
這篇文章主要介紹了安卓監(jiān)聽屏幕的橫豎翻轉(zhuǎn)實(shí)現(xiàn)方法,有需要的朋友可以參考一下2013-12-12
Android實(shí)現(xiàn)城市選擇三級(jí)聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)城市選擇三級(jí)聯(lián)動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
android USB如何修改VID具體實(shí)現(xiàn)
在android 設(shè)備的Linux 內(nèi)核中把 USB 驅(qū)動(dòng)的 PID VID 修改以后,也許之前的adb工具就不能識(shí)別設(shè)備了,會(huì)打印出"device not found"的提示2013-06-06

