亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Android中的圖片優化完全指南

2019-10-21 21:36:20
字體:
來源:轉載
供稿:網友

前言

圖片作為內存消耗大戶,一直是開發人員嘗試優化的重點對象。Bitmap的內存從3.0以前的位于native,到后來改成jvm,再到8.0又改回到native。fresco花費很多精力在5.0系統之前把Bitmap內存改回到native,高版本上面則遵循系統實現,卻又被官方打臉。

jvm每個進程都有內存上限,而native則沒有限制(不是沒有影響,至少不會oom),所以把內存大戶Bitmap挪到native可能是很多人的夢想,但native的管理和實現明顯比jvm更為復雜,除非有現成實現,很少有人去動這一塊。行業里面的大部分圖片庫都沒有涉及這塊,大部分的程序員也秉著夠用就好的態度用了很多年,這說明程序員也是會偷懶的。官方的策略修改到底原因幾何,其實我也沒搜到相關說明,有知道的同學歡迎留言。

概念

圖片占用的內存:圖片高度 * 圖片寬度 * 一個像素占用的內存大小這個公式代表一個圖片最終占用的內存大小,項目中的優化圖片占用內存都是通過這個三個參數來優化的。

第一條規則:把Bitmap保存到native

一個app里面的圖片都會有尺寸,一般情況下面圖片的尺寸就是view的大小,而view的大小在我們使用dp單位后在不同的機器上面表現出來的實際像素都有差別,為了節約流量開銷,加快返回速度,同時符合按需加載的原則,我們應該只加載實際view尺寸大小的圖片。一般圖片存儲提供商都會提供在線壓縮服務,我們只需要在請求鏈接里面加上參數即可。這里還有個問題我們一般請求加載圖片的代碼都是寫在Activity的onCreate,或者Adapter的getView函數里面,這個時候其實是獲取不到view尺寸的(還未measure),這里有幾種做法:

使用目測:比如一個列表是左右圖片布局的,那就可以請求屏幕一半寬度的尺寸圖片

view使用了固定尺寸:這個沒有問題,我們直接拿getLayoutParams()的width和height就可以了

view的maxWidth/maxHeight:view無法固定尺寸,我們可以在xml里面給view配置maxWidth/maxHeight來指導圖片庫加載什么尺寸的圖片

加載圖片前先measure:不怎么推薦,因為圖片加載出來后view還得measure一次

一般做法是給圖片加載庫包裝一層,根據傳進來的url判斷是否已經指定大?。ㄩ_發者當然可以決定想加載多大圖片),如果還未指定則使用上面的策略進行動態調整,如果最后還是沒能加上縮放參數,則有個兜底策略,不加載超過屏幕尺寸大小。

第二條規則:按需請求

做了上面按需加載后還有個問題,會發現有時候不同的頁面需要加載同一個圖片url,但在尺寸上面有細微差別,結果導致請求重復(一般圖片加載庫都是url作為緩存key),有點弄巧成拙,反倒浪費了流量和時間。這種情況我們需要做些微調。對于A頁面圖片尺寸是200x200,對于B頁面圖片尺寸是180x180,我們認為可以使用200x200的圖片縮放到180x180,這有兩種做法:第一種是讓開發者始終都去加載稍微大一點的圖,這個要求有點高,一個頁面開發的時候很難前后聯系。第二種是修改圖片加載庫,自動完成這個事情。后者自然合理,修改圖片加載庫在決定使用緩存的那一步判斷是否有比自己大的緩存已經存在即可,當然這個策略可以每個產品自己調整,比如也可以認為已經存在的緩存尺寸小于一定值也是可以接受也是可以的。還有復雜的情況比如緩存圖片高寬比和要加強的不一樣如何處理等等,策略都可以自己定,但一定有必要做這個事情。

這里還要補充一點,大型產品一般圖片域名會有好幾個,用來做鏈路擇優用的,一定要記得緩存的時候用來做key的url要去掉域名影響。

再補充一點,有些特殊的使用場景可以考慮采用上面說的第一種方式來做,舉個例子比如一個操作一定會加載100x100的圖,然后也一定會等會加載500x500的同一張圖,這種場景下面按第二種方式來處理顯然會加載兩次,但如果開發者這2個位置寫死都加載500x500則明顯更好一些。所以方法是死的,人是活的,要看實際使用場景。

還有一些特殊場景,比如程序里面有兩個進程,A進程會加載500x500的圖,B進程會加載不管什么尺寸的同一張圖,默認情況下面這2個請求會同時發出,這就很可能會造成重復請求,這種情況下面需要做一點跨進程同步,或者簡單一點其中一個進程請求做一點延遲處理。

第三條規則:合并相似請求

實在不得已要從服務端加載大圖或者原始尺寸下來,或者因為上面說的策略故意加載大圖下來,在decode的時候要進行采樣,這個是老生常談了,使用options.inJustDecodeBounds來獲取原始尺寸,然后按需使用options.inSampleSize來采樣圖片到接近view尺寸。

第四條規則:按需加載

Bitmap在decode的時候可以使用inPreferredConfig指定配置格式,常見的有:

參數取值含義ALPHA_8圖片中每個像素用一個字節(8位)存儲,該字節存儲的是圖片8位的透明度值RGB_565圖片中每個像素用兩個字節(16位)存儲,兩個字節中高5位表示紅色通道,中間6位表示綠色通道,低5位表示藍色通道ARGB_4444圖片中每個像素用兩個字節(16位)存儲,Alpha,R,G,B四個通道每個通道用4位表示ARGB_8888圖片中每個像素用四個字節(32位)存儲,Alpha,R,G,B四個通道每個通道用8位表示

對于質量細節要求比較高的圖片可以使用ARGB_888,這也是fresco的默認配置。而對于JPG圖片可以使RGB_565,從上面可以看出內存占用之間減少一半,非常有吸引力,而app里面事實上大部分應該都是JPG。但往往在和視覺的PK當中開發往往敗下陣來,降低了圖片質量不行?。¢_發總是鍥而不舍,我們可以建議采用這樣的策略:對于尺寸小于一定尺寸的JPG(比如300),我們使用565,而對于大圖為了保留細節我們仍然使用8888。還是那句話策略是活的。

第五條規則:進一步按需加載

使用三級緩存機制,內存磁盤網絡,這也是官方推薦的方式。內存緩存旨在加快訪問速度,磁盤緩存避免反復請求。關于這一點就不在贅述了,基本開源圖片庫都會這么做

第六條規則:使用三級緩存機制

很多場景下面我們需要顯示圖片的一部分,或者進行圖片效果疊加,比如做個倒影之類的。很多同學上來就準備createBitmap,然后把疊加效果繪制到這個臨時Bitmap,或者從原始Bitmap里面先剪一部分出來生成一個新的Bitmap,再設給ImageView?;蛘呤褂胏reateScaledBitmap進行縮放。更不小心的同學可能直接把這些操作代碼寫在UI線程,然后寫在子線程又比較麻煩,這邊推薦的是使用自定義繪制,canvas有個drawBitmap方法可以把某個區域繪制到指定位置。疊加效果也可以完全使用自定義view來自己draw,這樣不會有臨時Bitmap生成,效率會更高。

如果自定義view有困難,我們可以使用Drawable,只要能拿到canvas,這兩種做法是一樣的。
這里列舉一些實例,好讓大家可以進一步理解:

一個按鈕有普通和按下狀態,按下是普通狀態上面疊加一個遮罩,不需要切兩張圖,按下狀態的Drawable可以使用自定義Drawable的canvas先繪制普通狀態的圖,再在上面繪制一層顏色?;蛘甙聪聽顟B使用LayerDrawable,這個Drawable自動幫你做了這個事情

需要把Bitmap的[0,0,200,200]的區域顯示到ImageView上面,使用canvas.drawBitmap(bitmap, [0,0,200,200], [0,0,圖片寬,圖片高],paint)

繪制倒影,這個邏輯性比較強了,這里就不具體展開,canvas的操作學習下,結合局部繪制其實很簡單

有個圖片,需要在左上角顯示一個角標,正常情況下面需要在左上角擺一個view,如果使用Drawable自定義繪制,canvas畫一下就好,類似下面的示例代碼。

給大家一個自定義繪制的例子,隨心組合:

class WithLineDrawable extends DrawableWrapper { private MyConstantState mMyConstantState; private boolean mForTop; private Paint mLinePaint = new Paint(); public WithLineDrawable(Drawable drawable, boolean forTop) { super(drawable); mLinePaint.setColor(getLineColor()); mForTop = forTop; } @Override public void draw(Canvas canvas) { super.draw(canvas); if (mForTop) {   canvas.drawLine(0, 0, getBounds().width(), 0, mLinePaint);  } else {   canvas.drawLine(0, getBounds().height(), getBounds().width(), getBounds().height(), mLinePaint);  } } @Nullable @Override public ConstantState getConstantState() { if (mMyConstantState == null) { mMyConstantState = new MyConstantState();  } return mMyConstantState; } class MyConstantState extends ConstantState { @NonNull  @Override public Drawable newDrawable() { return new WithLineDrawable(getWrappedDrawable().getConstantState().newDrawable(), mForTop);  } @Override public int getChangingConfigurations() { return 0;  } }}

一定要把觀念從Bitmap轉變到Drawable,當還在費勁心思Bitmap該如何處理的時候,想想Drawable里面如何使用canvas進行各種自定義繪制。

第七條規則:多使用自定義View或者Drawable自定義繪制

圖片格式發展到今天已經非常多樣了,目前很多開源庫都支持了webp來代替jpg和gif,webp在壓縮率上面有很多優勢,雖然解碼上面略遜一籌,經過我們測試還是很不錯的。也是推薦大家使用,不論是網絡圖片下載還是apk內置,用來代替jpg很合適,而代替png則還需要一些時間,主要是低版本系統對于透明webp還有些兼容問題。Android P上面支持了heif格式也是想代替jpg,不過這個格式目前還沒仔細研究過。

對于內置apk的圖標類,則推薦使用svg,不再需要切幾套圖,而且非常小,官方使用的compat包里面解碼svg會做緩存,也進一步提升性能。不過也正因為此盡量不要一個圖片使用過多不同尺寸。大部分的圖標都使用代碼代替圖片后,apk大小可以明顯減少,這也符合我們的原則:能程序畫的就絕不切圖。

第八條規則:使用更好的圖片格式

很多時候我們需要給圖標換色,關于顏色混合有一套理論,官方很早就支持,使用ColorFilter,后來compat包里面出了個tint,所以如果有顏色混合處理的相關邏輯,千萬不要去生成臨時Bitmap,使用類似如下代碼:

//1:通過圖片資源文件生成Drawable實例Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher).mutate();//2:先調用DrawableCompat的wrap方法drawable = DrawableCompat.wrap(drawable);//3:再調用DrawableCompat的setTint方法,為Drawable實例進行著色DrawableCompat.setTint(drawable, Color.RED);

第九條規則:使用著色API

內置apk的圖片資源非常多,總有一些常規圖片仍然需要使用jpg或者png,我們要想辦法進一步壓縮他們,這樣可以有效控制apk大小,這里推薦使用ImageOptim,這個工具集合了很多種壓縮方式,效果顯著。

第十條規則:使用壓縮工具

后記:

很多面試的時候問如何做圖片加載優化,他們會回答recycle

bitmap,事實上這個操作要很謹慎,一不留神就會導致出問題。大部分的應用不太會干這個事情,吃力不討好,交給jvm垃圾回收多好。圖片解碼還有一些參數可以優化,比如inBitmap,這里就不具體展開了。

總結下

  • 把Bitmap保存到native
  • 按需請求
  • 按需加載
  • 合并相似請求
  • 使用三級緩存機制
  • 多使用自定義View或者Drawable自定義繪制
  • 使用更好的圖片格式
  • 使用著色API
  • 使用壓縮工具

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲女人天堂成人av在线| 国产精品久久一区| www.欧美精品一二三区| 中文字幕欧美亚洲| 日韩麻豆第一页| 国产a∨精品一区二区三区不卡| 亚洲精品国产精品乱码不99按摩| 欧美性受xxxx白人性爽| 中文欧美日本在线资源| 午夜精品一区二区三区在线| 伊人久久久久久久久久| 国产精品国产亚洲伊人久久| 久久亚洲欧美日韩精品专区| 久99久在线视频| 久久精品中文字幕电影| 亚洲成人中文字幕| 亚洲成**性毛茸茸| 亚洲天堂视频在线观看| 欧美中文字幕在线播放| 亚洲欧洲第一视频| 91中文在线视频| 国产成人精品999| 精品久久久久久久久久ntr影视| 亚洲福利视频在线| 成人观看高清在线观看免费| 亚洲精品一区二三区不卡| 日韩毛片在线观看| 亚洲www视频| 亚洲男女性事视频| 成人网中文字幕| 免费99精品国产自在在线| 欧美香蕉大胸在线视频观看| 国产视频久久久久| 中文字幕精品影院| 久久福利视频导航| 欧美噜噜久久久xxx| 久色乳综合思思在线视频| 欧美国产日韩xxxxx| 欧美日韩午夜激情| 成人a免费视频| 成人免费看黄网站| 欧美性生交xxxxx久久久| 欧美裸身视频免费观看| 日韩在线视频线视频免费网站| 亚洲国产又黄又爽女人高潮的| 日韩中文字幕在线视频播放| 日韩美女视频免费在线观看| 欧美综合在线观看| 亚洲人成电影网站色| 亚洲美女久久久| 国产精品久久久久99| 国产精品久久电影观看| 91麻豆国产语对白在线观看| 久久久亚洲精选| 亚洲欧美日韩国产中文| 在线成人一区二区| 97精品伊人久久久大香线蕉| 欧美性xxxxhd| 国产精品电影网站| 国产99视频精品免视看7| 欧美一级电影久久| 欧美日韩免费在线| 国产91精品高潮白浆喷水| 久久视频在线看| 九色精品免费永久在线| 久久男人的天堂| 日韩理论片久久| 久久免费国产精品1| 亚洲自拍av在线| 欧美一乱一性一交一视频| 亚洲成av人影院在线观看| 亚洲亚裔videos黑人hd| 欧美日韩综合视频网址| 欧美极度另类性三渗透| 午夜精品久久久久久99热| 国产精品成熟老女人| 国产99久久精品一区二区永久免费| 国产欧美日韩亚洲精品| 国产亚洲欧美一区| 搡老女人一区二区三区视频tv| 日韩av中文在线| 亚洲成人久久久| 热re91久久精品国99热蜜臀| 亚洲色图25p| 97视频免费在线观看| 国内揄拍国内精品| 国产精品视频播放| 久久视频精品在线| 国产成人精品电影| 欧美日韩国产区| 91精品啪aⅴ在线观看国产| 亚洲精品永久免费| 成人在线观看视频网站| 亚洲国产天堂久久国产91| 国产欧美婷婷中文| 日韩在线免费观看视频| 日韩欧美成人区| 亚洲xxxxx| 久久久在线免费观看| 91精品国产91久久久久久不卡| 久久国产精品网站| 亚洲欧美日韩中文在线制服| 国产日韩综合一区二区性色av| 亚洲免费av电影| 久久99国产综合精品女同| 一本色道久久88亚洲综合88| 国产成人精品午夜| 日韩免费精品视频| 久久久噜久噜久久综合| 国产精品专区一| 97久久久免费福利网址| 欧美精品亚州精品| 亚洲a区在线视频| 亚洲国产精品va在线| 青草青草久热精品视频在线网站| 美女av一区二区| 久久久www成人免费精品| 亚洲人成电影在线播放| 久久中国妇女中文字幕| 欧美日韩免费网站| 日韩国产高清视频在线| 91精品综合久久久久久五月天| 91久久夜色精品国产网站| 91精品视频在线播放| 国产精品久久久久9999| 欧美黑人巨大精品一区二区| 日本精品久久久久久久| 久久在线视频在线| 8090理伦午夜在线电影| 国产精品成人在线| 热re99久久精品国产66热| 国产精品中文在线| 国产视频观看一区| 国产亚洲视频在线| 久久精品视频亚洲| 国产欧美精品一区二区三区-老狼| 欧美日在线观看| 色视频www在线播放国产成人| 精品久久中文字幕| 91香蕉亚洲精品| 国产成人拍精品视频午夜网站| 国产综合视频在线观看| 亚洲欧美制服另类日韩| 欧美一区二区三区免费观看| 超薄丝袜一区二区| 国产专区精品视频| 亚洲成人三级在线| 理论片在线不卡免费观看| 懂色av中文一区二区三区天美| 国产精品福利无圣光在线一区| 亚洲aa中文字幕| 日韩欧美成人区| 亚洲激情电影中文字幕| 成人免费网站在线看| 欧美激情精品久久久久久黑人| 国产99久久精品一区二区 夜夜躁日日躁| 国产亚洲精品美女久久久| 日韩av大片免费看| 国产精品亚洲网站| 成人有码在线播放| 欧美视频专区一二在线观看| 久久九九精品99国产精品| 欧美高清电影在线看| 国产va免费精品高清在线|