Bloqueo de la aplicación causado por una imagen

prefacio

        Los recursos de imágenes proporcionados por el UE generalmente se usan directamente excepto para la compresión. Sin embargo, una vez que UE proporcionó una imagen pequeña de tamaño 1*1, provocó un bloqueo de la interfaz de usuario de la aplicación. Me gustaría compartir las razones y soluciones para este problema a continuación.

Descripción del problema

java.lang.llegalArgumentException: Dimensions must be positive! provided (0, 0)

El tamaño requerido por el sistema es positivo, pero el tamaño proporcionado por el sistema es 0, es decir, el tamaño de 0 causa el problema. Esto requiere análisis y posicionamiento en combinación con la información de la pila.

Ubicación de la causa

        La información de la pila es la siguiente. Aquí solo se muestra la pila de la API del sistema Android y se omite el lugar donde se llama al código comercial, pero esta información es suficiente para localizar la causa.

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)
......
复制代码

Se puede ver en la línea 2 de la información de la pila que el problema finalmente es causado por el método setTargetSize en la clase ImageDecoder. Abra el código fuente de Android aquí para ver la implementación específica del método setTargetSize, de la siguiente manera.

public void setTargetSize(@Px @IntRange(from = 1) int width,                           
                          @Px @IntRange(from = 1) int height) {    
       if (width <= 0 || height <= 0) {      
             throw new IllegalArgumentException("Dimensions must be positive! " + "provided (" + width + ", " + height + ")");                
       }                            
         mDesiredWidth = width;                
         mDesiredHeight = height;
}
复制代码

Se puede ver que cuando ancho = 0 o alto = 0, el método setTargetSize generará una excepción. Entonces, ¿por qué el ancho y la altura son iguales a 0? Continúe mirando hacia abajo de acuerdo con la información de la pila. La implementación del código fuente del método computeDensity es la siguiente.

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) {             return srcDensity;             
        }                      

        final int dstDensity = src.computeDstDensity();             
        if (srcDensity == dstDensity) {                       
            return srcDensity;             
        }                      

        if (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P) {                    
           return srcDensity;             
        }                      

        float scale = (float) dstDensity / srcDensity;             
        int scaledWidth = (int) (mWidth * scale + 0.5f);             
        int scaledHeight = (int) (mHeight * scale + 0.5f);             
        this.setTargetSize(scaledWidth, scaledHeight);             
        return dstDensity;
}
复制代码

El ancho y el alto de setTargetSize se pasan a través del método computeDensity. mWidth y mHeight son las dimensiones de la imagen, ambas son 1.

Es decir, las fórmulas de cálculo de ancho y alto son (int)(1 * escala + 0,5f). Aquí encontrará que el culpable de que el ancho y la altura sean 0 es la escala.        

La fórmula de cálculo de la escala es (flotante)dstDensity/srcDensity. De acuerdo con la descripción de dstDensity y srcDensity en la API del sistema, dstDensity es la densidad de píxeles de la pantalla y srcDensity es el parámetro de densidad que pasa la aplicación, según el archivo de imagen que se coloque.

image.pngPorque la imagen se coloca en la carpeta xxhdpi, es decir, la densidad de origen es 480.        

El valor de dstDensity debe analizarse de acuerdo con la situación específica del sistema de telefonía móvil.        

假如一台手机的分辨率为19201080,4.5英寸。dstDensity的值就为(19201920 + 1080*1080)开根号、再除以4.5,约等于489.5。此时scale=489.5 / 480 = 1,计算得到的宽、高也会大于0,这种情况是不会抛出异常的。        

但假如是在宽度较大的平板,尺寸是13.5,那么得到的dstDensity约等于163。在这种情况下,根据宽、高的计算公式:(int)(1 * (163 / 480) + 0.5f) = 0。这时候系统就会抛出异常,导致APP crash。

解决方式

原因定位后,有两种解决方案:

  • 方案1:找UE换一张尺寸不低于3*3的图片。
  • 方案2:删除该1*1的图片。

和UE沟通后,该图片下个版本不会再使用,删除不会产生影响,于是采用了方案2。问题解决。

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

Supongo que te gusta

Origin juejin.im/post/7087930757796069413
Recomendado
Clasificación