java.lang.IllegalArgumentException: x + width must be 小於等於 bitmap.width()錯誤的分析,解決

場景

最近在寫一個滑動驗證登錄的View,遇到了一個很有趣的BUG
在這裏插入圖片描述
我需要從背景圖中1處扣除一個小圖,放在2處。在摳圖的時候,遇到了BUG。

java.lang.IllegalArgumentException: x must be < bitmap.width()

這個報錯的意思是,當前我要扣的圖尺寸要比原圖比背景圖大。這就很奇怪,小方塊的尺寸明明比背景圖小啊。

分析

記住,一切報錯的問題的答案,在源碼中一定可以找到!因此我們來看看是源碼中哪裏拋出了這個異常

public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
            @Nullable Matrix m, boolean filter) {

        checkXYSign(x, y);
        checkWidthHeight(width, height);
        if (x + width > source.getWidth()) {
            throw new IllegalArgumentException("x + width must be <= bitmap.width()");
        }
        if (y + height > source.getHeight()) {
            throw new IllegalArgumentException("y + height must be <= bitmap.height()");
        }
     
     後面的省略。。。。。。   

這段代碼值得好好說下,因爲每天在看線上崩潰日誌時,偶爾能看到這裏出錯的場景。
首先是:

checkXYSign(x, y);
checkWidthHeight(width, height);

這兩行主要就是校驗當前Bitmap 的繪製的位置、尺寸是否是正常的。也就是說x、y、width、height 都必須要大於0,否則就會報錯,例如:

throw new IllegalArgumentException("x must be >= 0");
throw new IllegalArgumentException("width must be > 0");

接下來就是今天的主角:

throw new IllegalArgumentException("x + width must be <= bitmap.width()");

x : 要創建的Bitmap的x 座標;
width : 要創建的Bitmap的寬度。
Bitmap.width(): 原圖的寬度

翻譯下報錯的意思,就是說,當前你要從主圖中一個x,y的位置去截圖一個width大小的圖,但你要截取的圖的位置不在或者超出了主圖的範圍,然後就報錯了。

那什麼情況會出現截圖不在主圖的範圍 ?
答案:就是要繪製的Bitmap的寬、高要比View的寬、高小!(或者說不一致)
我們在給View 繪製Bitmap 時,會有這樣一種操作:

mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bilibili);
canvas.drawBitmap(mBgBitmap,null,new Rect(0,0,mWidth,mHeight),mBgPaint);

這個操作其實就是講圖片的原圖繪製到了View上,假設這張圖是600* 200。而View的是1080 * 300。雖然你看到了這張圖已經鋪滿了整個View,但這並不代表背景圖的Bitmap的寬高就等於View的寬高!!!
如果此時,我從橫座標 x = 550 ,截取一張寬度100 的圖。這個時候你會發現:
550 + 100 > 600 ; 即 x + width > bitmap.width()
然後就崩了。。。。。。

解決這個問題的辦法,最好就是將背景的圖的Bitmap 的大小設置成和View的大小一致,這樣後面就好操作,也就不用考慮過多座標的問題。

擴展

既然說到設置Bitmap 的大小,那麼我在獲取到 bitmap後(使用的是BitmapFactory.decodeResource)直接設置可以嗎 ?

mBgBitmap.setWidth(1000);

答案是不行:你會看到

new IllegalStateException("only mutable bitmaps may be reconfigured");

繼續從源碼中找答案:

public void reconfigure(int width, int height, Config config) {
        checkRecycled("Can't call reconfigure() on a recycled bitmap");
        if (width <= 0 || height <= 0) {
            throw new IllegalArgumentException("width and height must be > 0");
        }
        if (!isMutable()) {
            throw new IllegalStateException("only mutable bitmaps may be reconfigured");
        }
        省略

我們在給Bitmap設置寬度時,最終會調用上面的代碼,其中有句

!isMutable()

當前值是否可變,默認是不可變的,那啥時候可以變?
答案就是在使用createBitmap()方法創建Bitmap時,下面截圖看最清晰
在這裏插入圖片描述
使用這種方式創建,一開始就設置Bitmap的相關屬性是可變的。

總結

Bitmap 作爲我們經常打交道的一個類,其源碼非常有必要看!

問:你看源碼的目的是啥?
答:兩個目的。1:學習Android 源碼裏的一些功能的實現以及框架的設計思路。2、解BUG,BUG的產生就是你沒有按照Android 設定的規則去寫,看源碼就是要了解規則。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章