java.lang.IllegalArgumentException: x + width must be 小于等于 bitmap.width()错误的分析,解决

场景

最近在写一个滑动验证登录的View,遇到了一个很有趣的BUG
java.lang.IllegalArgumentException: x + width must be 小于等于 bitmap.width()错误的分析,解决_第1张图片
我需要从背景图中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 设定的规则去写,看源码就是要了解规则。

你可能感兴趣的:(开发经验,Android开发)