一直以來Bitmap在Android中的處理都是非常棘手的。如果我們直接將一個完整分辨率的圖片加載到內(nèi)存中它會占用非常高的內(nèi)存(Bitmap的占用內(nèi)存大小請參照《Android性能調(diào)優(yōu)(5)—Bitmap內(nèi)存模型》),如果是一張巨圖則極有可能直接OOM,比如我們今天要給大家說的一張440 * 10260像素,Bitmap.Config.ARGB_8888圖片。
占用內(nèi)存大?。?40 * 10269 * 4 / 1024 / 1024 =17.2M(不考慮Density影響)。這么大的一張圖片如果直接加載到內(nèi)存中后果可想而知。
一、說在前面
前面我們分別用兩篇文章介紹了《Android性能調(diào)優(yōu)(5)—Bitmap內(nèi)存模型》與《Android性能調(diào)優(yōu)(6)—Bitmap優(yōu)化》。本篇也是我們Bitmap專題的最后一篇文章。可見Bitmap在Android中確實是一個難點。
在《Android性能調(diào)優(yōu)(6)—Bitmap優(yōu)化》介紹了對Bitmap的優(yōu)化;優(yōu)化的本質(zhì)是先對Bitmap進行縮放然后進行多級緩存以及復(fù)用。但是如果我們應(yīng)用中就是要加載顯示一張大圖或者巨圖我們該怎么辦呢?
二、巨圖加載
那有沒有辦法在占用較少內(nèi)存情況下完整顯示整張巨圖呢?其實我們可以換種思路來完成,那就是對于一張巨型圖片我們可否每次指定一塊區(qū)域加載顯示,然后通過改變這個區(qū)域完成整張巨圖的加載呢?這樣內(nèi)存中只有完整圖片的一塊區(qū)域。
三、區(qū)域加載
1、BitmapRegionDecoder
其實從名字我們也可以看出:指定Bitmap區(qū)域進行解碼,沒錯它主要用于顯示圖片的某一塊矩形區(qū)域,如果需要顯示某個圖片的指定區(qū)域,那么這個類非常合適。
它的用法也非常簡單,既然是顯示圖片的某一塊區(qū)域,那么至少需要兩個方法:1、設(shè)置圖片,2、設(shè)置顯示區(qū)域。
接下來通過自定義一個可以加載巨圖的View展開說明:
2、設(shè)置圖片
前面說到至少需要兩個方法:1、設(shè)置圖片 2、指定顯示區(qū)域
我們先來看如何設(shè)置圖片:

mOptions實際就是BitmapFactory.Options
它的使用我們在《Android性能調(diào)優(yōu)(6)—Bitmap優(yōu)化》已經(jīng)詳細介紹過了;設(shè)置inJustDecodeBounds為ture(只解碼圖片的尺寸)。然后得到圖片寬高,并且設(shè)置Bitmap是可以被復(fù)用的。然后創(chuàng)建BitmapRegionDecoder的實例對象。最后調(diào)用requestLayout()方法,reqeustLayout會重新測量我們的布局也就是會執(zhí)行View的onMeasure()。
3、指定顯示區(qū)域

在onMeasure方法中我們需要指定要加載圖片的區(qū)域Rect的四個頂點位置。
由于我們不需要對Bitmap的的位置重新擺放,所以不許要重寫onLayout方法,但是自定義View要繪制一張圖片該怎么辦?想必大家能夠猜到:

首先設(shè)置Bitmap的復(fù)用,然后根據(jù)指定區(qū)域以及Options來解碼一張圖片,最后通過Canvas繪制到View中。
說道這里我們就將一張巨型圖片的某個區(qū)域顯示到View中了。但是我們僅僅顯示了指定區(qū)域,而且是較小的一部分區(qū)域,如果想要完整預(yù)覽整張圖片該如何處理呢?
四、改變區(qū)域完成巨圖加載
1、Scroller + GestureDetector
上面說到我們通過Rect指定顯示區(qū)域,那通過改變要顯示的區(qū)域位置不就可以完成整張圖片的加載了?
所以借助手勢GestureDetector與Scroller(滑動幫助)來完成這一功能。
首先我們將事件交由GestureDetector處理:

在GestureDetector的onScroll方法中:

重新指定上下兩個頂點位置,然后調(diào)用invalidate進行重新繪制。
在GestureDetector的onFling方法:

指定手指離開的后的滑動慣性。
如果手指按下,此時我們希望停止滑動:

重寫View的computeScroll計算View如何滑動:

這樣我們通過BitmapRegionDecoder每次只加載顯示一塊區(qū)域的Bitmap,然后配合GestureDetector與Scroller完成手勢滑動改變Rect完成View的滑動效果。至此如何加載顯示一張巨圖就實現(xiàn)了。
薦:https://www.linuxidc.com/Linux/2016-01/127276.htm
2、附上完整代碼: