前言
UE提供的图片资源,一般除了做下压缩外,都是直接使用的。不过有一次UE提供了一张1*1尺寸的小图片后,却引发了app一个UI crash。下面想分享下该问题的原因及解决方案。
问题javaee描像素述
java.lang.llegalArgumentException: Dimensions mustappointment be positive! provided (0, 0)
系统要求的尺寸是正的,但提供系统的尺寸却是0,即尺寸是0导致了问题的出现。这需要结合堆栈信息进行分析、定位。
原因定application位
堆栈信息如下。这里只展示了Android系统API的堆栈,业务代码调用的地方被省略了,不过这些信息已经足够定位原因。
java.lang.llegalArgumentException: Dimensions must be positive! provided (0, 0)
at android.graphics.ImageDecoder.setTargetSize(lmageDecoder.java:1033)
at android.graphics.lmageDecoder.computeDensity(lmageDecoder.java:1823)
at android.graphics.ImageDecoder.decodeDrawablelmpl(lmageDecoder. java:1670)
at android.graphics.ImageDecoder.decodeDrawable(lmageDecoder.java:1645)
at android.content.res.Resourceslmpl.decodelmageDrawable(Resourceslmpl.java:766)
at android.content.res.Resourceslmpl.loadDrawableForCookie(Resourceslmpl.java:839)
at android.content.res.Resourceslmpl.loadDrawable(Resourceslmpl.java:631)
at android.content.res.Resources.loadDrawable(Resources.java:897)
at android.content.res.TypedArray.getDrawableForDensity(TypedArray.java:955)
at android.content.res.TypedArray.getDrawable(TypedArray.java:930)
at android.widget.ImageView.(lmageView.java:189)at android.widget.ImageView.(lmageView.java:172)
......
由堆栈信息的第2行可见,最终引发问题的是Ima像素射击geDecoder类下的setT像素游戏argetSize方法。这里打开Android的源码看看se像素tTargetSize方法的具体实现,如下。
public void setTargetSize(@Px @IntRange(from = 1) int width,
@Px @IntRange(from = 1) int height) {
if(width<=0||height<=0){
thrownewIllegalArgumentException("Dimensionsmustbepositive!"+"provided("+width+","+height+")");
}
mDesiredWidth=width;
mDesiredHeight=height;
}
可见,当widappstoreth源码中的图片=0或Androidheight=0,set源码编辑器下载TargetSize方法会抛出异常。那么为什么width、height会等于0呢?根据堆栈信息继android是什么系统续往下看。computeDenappstoresity方法的源码实现如下。
private int computeDensity(@NonNull Source src) {
if (this.requestedResize()) {
return Bitmap.DENSITY_NONE;
}
final int srcDensity = src.getDensity();
if (srcDensity == Bitmap.DENSITY_NONE) {
return srcDensity;
}
if (mIsNinePatch && mPostProcessor == null) {
return srcDensity;
}
Resources res = src.getResources();
if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) { returnsrcDensity;
}
finalintdstDensity=src.computeDstDensity();
if(srcDensity==dstDensity){
returnsrcDensity;
}
if(srcDensity<dstDensity&&sApiLevel>=Build.VERSION_CODES.P){
returnsrcDensity;
}
floatscale=(float)dstDensity/srcDensity;
intscaledWidth=(int)(mWidth*scale+0.5f);
intscaledHeight=(int)(mHeight*scale+0.5f);
this.setTargetSize(scaledWidth,scaledHeight);
returndstDensity;
}
setTargetSize的width、height就是通过computeDensity方法传入。mWidth、mHeight是图片的尺寸,两个都为1。
即宽、高的计算公式都为(int)(1 * scale + 0.5f)。到这java语言里会发现,导致宽、高为0的罪魁祸首是sca像素画生成器le。
scale的计算公式为(float)dst像素生存者2Density/srcDensity。根据系统API对dstDensity、srcDensity的描述可知,dstDensity为屏幕像素密度,srcDensity为APP传入的密度参数、取决于放入了哪一个图片文件。
因为该图片放进了xxhdpi文件夹中,即srcDensity为480。
dstDensity这个值就需要根据手机系统的具体情况来分析。
假如一台手机的分辨率为19201080,4.5英寸。dstDensity的值就为java是什么意思(19201920+ 1080*appetite1080)开根号、再除以4.5,约等于489.5。此时scale=appearance489像素射击下载.5 /480 = 1,计算得java语言到的像素涂色宽、高也会大于0,这种情况是不会抛出异常的。
但假如是在宽度较大的平板,源码时代尺寸是13.5,那么得到的dstDensity约等于163。在这种情况下,根据宽、高的计算公式:(int)(1 * (163 /480) + 0.5f) = 0。这时候系统就会抛出异常,导致APP crash。
解决方appear式
原因定位后,有两种解决方案:像素画生成器
- 方案1:找UE换一张application尺寸不低于3*3的图片。
- 方案2:删除该1*1的图片。
和UE沟通后,该图片下个版本不会再使用,删除不会产生影响,于是采用了方案2。问题解决。
欢迎关注公众号度熊君,一起分享交流。