前言

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传入的密度参数、取决于放入了哪一个图片文件。

一张图引发的App crash
因为该图片放进了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。问题解决。

欢迎关注公众号度熊君,一起分享交流。