Android 中圖片的加載是個很頭疼的問題懈玻,不過還好我們有Glide(逃跑臉..)
不過當(dāng)你有要顯示一張遠超手機尺寸的超大圖片的需求時蛤吓,Glide也幫不了你闲昭,我現(xiàn)在慌得一B(躺草地)
為什么慌呢更耻,因為長這樣
可以看到脱羡,首先顯示上有問題找都,其次整張圖片加載到了內(nèi)存中唇辨,我們用 Android Profiler 抓一下看看占了多少內(nèi)存
我滴乖乖,占了快 34M能耻,還好我手機分配給應(yīng)用的內(nèi)存夠大赏枚。那么要如何解決這兩個問題呢?且看分解:
一.圖片加載占用內(nèi)存的計算
影響圖片在內(nèi)存中大小的有三個元素:
1.圖片原始寬高
2.圖片的色彩空間
3.圖片的縮放比
(1)圖片原始寬高:它們的乘積代表圖片的總像素點數(shù)
(2)圖片的色彩空間:每個像素點的信息嚎京,占用多少字節(jié)嗡贺,比如 Bitmap.Config.ARGB8888 代表每個色彩通道占8bit位 總共就是 4個字節(jié),可以在 BitmapFactory.Options 的 inPreferredConfig 屬性進行調(diào)節(jié)鞍帝,常用的還有 Bitmap.Config.RGB565
(3)圖片的縮放比:對圖片原始寬高的縮放诫睬,影響是次方級的,因為分別作用在了寬和高上帕涌。
它對應(yīng)的設(shè)置在 BitmapFactory.Options 的 inSampleSize 屬性摄凡,代表采樣率,默認為1蚓曼,必須大于1且為2的倍數(shù)
比如設(shè)置為 4 亲澡,則圖片的寬高都將變?yōu)樵嫉?1/4 ,那么總像素點數(shù)就變?yōu)榱嗽嫉?1/16
綜上總結(jié)的計算公式為:
圖片占用內(nèi)存= (原始寬 * 縮放比) * (原始高 * 縮放比) * 色彩空間
我們算一下剛才的圖進行驗證一下纫版,妹子圖寬 690px 高12287px 直接展示時 縮放比 inSampleSize =1 色彩空間ARGB8888
所以 內(nèi)存= 690 * 1 * 12287 * 1 * 4 = 33912120 和我們圖中抓的基本一致
平時在使用Glide進行加載圖片時床绪,框架里幫我們處理了縮放,Glide默認會加載并緩存具體尺寸的圖片,同時3.x版本的Glide默認使用RGB565的顏色通道癞己,這些都會幫助我們節(jié)省內(nèi)存
二.圖片分區(qū)域加載
既然我們一個屏幕展示不下這張圖膀斋,那么我們就顯示一部分,Android 中已經(jīng)提供了 解碼圖片部分區(qū)域的類 BitmapRegionDecoder,使用起來也很簡單
它提供了一系列靜態(tài)方法構(gòu)造實例
拿到實例后 通過 #decodeRegion() 方法痹雅,傳入一個 Rect 和 一個BitmapFactory.Options 參數(shù) 即可解碼出一張我們要的圖片解碼區(qū)域就是我們 Rect 指定的范圍仰担,拿到 Bitmap 后當(dāng)然可以為所欲為了
三.手勢檢測
我們已經(jīng)能夠展示大圖的部分區(qū)域了,那么勢必需要提供手勢操作讓用戶滑動或點擊來對圖片加載的區(qū)域或大小進行更新也就是需要自定義控件重寫 onTouchEvent方法進行處理
這里可以參考洋神的做法:https://blog.csdn.net/lmj623565791/article/details/49300989/
將手勢的處理交給 MoveGestureDetector 然后每次滑動完在 onDraw 里更新 解碼的區(qū)域 Rect
但是有兩個問題绩社,當(dāng)你將洋神的代碼跑起來后摔蓝,在 7.0 以上的手機上會發(fā)現(xiàn)圖劃不動,并且得到一個日志:
D/skia: --- SkAndroidCodec::NewFromStream returned null
經(jīng)Google 解決了問題:https://stackoverflow.com/questions/39316069/bitmapfactory-decodestream-from-assets-returns-null-on-android-7
大致就是 Google改了 BitmapFactory.cpp的代碼愉耙,我們需要在兩次decode 之間將 流重置一下 如下:洋神的 LargeImageView.java
第二個問題就是跑起來你會發(fā)現(xiàn)滑動起來很卡贮尉,體驗很差,因為動一動就一直在重繪劲阎。
解決方法就是不要繼承View 绘盟,我看世界地圖那個項目是繼承自 SurfaceView的鸠真,將繪制放到單獨的線程
四.開源項目解決方案
1.這個作者加了手勢縮放悯仙,雙擊等的處理,同時對顯示區(qū)域進行了緩存吠卷,實測很棒
https://github.com/kareluo/IntensifyImageView
2.一個N年前star的庫锡垄,但一直還沒用過
https://github.com/davemorrissey/subsampling-scale-image-view
五.另辟蹊徑的方式
使用WebView 進行展示,思路來自N年前聽說有個開源第三方微博客戶端是這么搞的
具體參考:https://blog.csdn.net/android_zhengyongbo/article/details/70225377