Recuento de métodos referenciados aumentado después de la modularización de la aplicación

16

AS: 3.5.3; Complemento Android Gradle: 3.5.0; Gradle: 5.6.2;

Observamos un aumento drástico en el número de métodos referenciados en nuestra aplicación después de dividir el módulo 'aplicación' en varios módulos pequeños. Pero lo extraño es que la adición de métodos referenciados por cada clase es menor que el total mencionado en Android Apk Analyzer Tool.

Para fines de prueba, he movido WebActivity.class del módulo 'aplicación' al módulo 'adaptadores' y el número de métodos referenciados aumentó en 181 métodos.

Para resumir:

app / WebActivity = 63546 Métodos reales referenciados pero que muestran 65394 métodos. adaptador / WebActivity = 63543 Métodos reales referenciados pero que muestran 65575 métodos.

Hemos observado que el 'recuento de métodos referenciados' aumentó en casi 10k después de agregar / dividir 4 nuevos módulos.

¿Cuál es el problema exacto?

¿Cómo la modularización de la aplicación puede aumentar el recuento de métodos referenciados tan drásticamente?

A continuación se muestran las capturas de pantalla que tomé de dos diferencias diferentes de solo APK: WebActivity se movió del módulo 'aplicación' al módulo 'adaptador' y aumentaron 181 métodos de referencia:

WebActivity en el módulo 'app' ingrese la descripción de la imagen aquí

Se movió WebActivity al módulo 'adaptador' ingrese la descripción de la imagen aquí

En las capturas de pantalla, ¿por qué la adición de métodos referenciados por cada clase (marcados en color rojo) no es igual al total dado en Apk Analyzer?

Rohit Surwase
fuente
He creado un problema, puedes rastrearlo aquí issuetracker.google.com/issues/146957168
Rohit Surwase

Respuestas:

9

He estado leyendo sobre el rendimiento del código y los parámetros de ajuste durante mucho tiempo. De hecho, los programas de Android son uno de mis enfoques.

Vamos a introducir al principio los conceptos básicos o más importantes en los que nos ayudan a llegar a una solución.

Como ha declarado el desarrollador de Android

El módulo se puede construir, probar y depurar independientemente

Por lo tanto, los módulos tienen sus propias dependencias y dependencias . Y puede explorarlo en el proyecto Hierarchy Viewer.

De hecho, el énfasis de la modularización en el mantenimiento es importante. A diferencia de Performance Matters, porque la modularización tiene este importante impacto:

  • Aumentar la profundidad de la herencia

Aquí hay un diagrama que tracé para aclararlo. Como puede ver, mientras usa un módulo discreto, para invocar el Método A, se 2N micro secscompara con un N micro secsmódulo discreto.

ingrese la descripción de la imagen aquí

Esta pregunta me viene a la mente de que los métodos referenciados cuentan lo que se relaciona con la profundidad de la herencia.

La respuesta es: aunque el uso de la modularización aumenta los métodos de referencia, pero en realidad no afecta el rendimiento de la aplicación y el principal problema posible es la profundidad de la herencia, que en la mayoría de los casos es ignorable .

Hago hincapié en que el aumento de los métodos de referencia en la modularización se debe a cada módulo Gradle y dependencias

¿Cómo la modularización de la aplicación puede aumentar el recuento de métodos referenciados tan drásticamente?

Condiciones en las que el analizador de APK de impacto es importante Métodos de referencia

También tenga en cuenta que la minificación y la reducción del código también pueden cambiar considerablemente el contenido de un archivo DEX después de compilar el código fuente.

Además de la declaración oficial anterior, quiero agregar otra condición en la que impacta el analizador APK que es:

¿Cuánto tiene experiencia el desarrollador en modularización?

La modularización es como un hogar en el que la arquitectura (desarrollador) define dónde debería estar la cocina y dónde debería estar el baño y dónde debería estar el WC. ¿Qué pasa si la arquitectura decide combinar WC y cocina? Sí, esto es un desastre.

Esto puede suceder durante la modularización si el desarrollador no tiene mucha experiencia.


Respondiendo a preguntas de OP Además de información adicional

Aquí respondo a las preguntas frecuentes en los comentarios

¿Por qué separar Gradle agregar al recuento de método referenciado? Y para una dependencia separada, si el resultado final es un APK único, entonces no creo que las dependencias duplicadas en la 'aplicación' y el módulo de características se agreguen al recuento de métodos referenciados.

Debido a que los módulos se pueden construir, probar y depurar, DEBEN tener sus propios Gradle & Dependencies.

Mientras se cumple el proyecto de varios módulos, el compilador genera varios .dexarchivos que incluyen:

  • un .dexarchivo para dependencias totalmente integradas
  • módulos .dexm

El .dexarchivo de dependencias es una integración de todos los módulos graduados

¡Veamos cómo un módulo gradle impacta el conteo final de Mothods referenciado!

hay 2 APK s con el mismo resultado pero diferencia en los recuentos de métodos referenciados.

Figura 1 Figura 2

Ambas son actividades vacías que tienen una 1.7kdiferencia en el recuento de métodos referenciados que es muy alta dependiendo de su funcionalidad. La diferencia clave está en Gradle de su módulo, uno de ellos fue configurado para

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}

Otro configurado para

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.2.0-alpha01'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
}

Aunque son solo actividades vacías, pero una diferencia mínima en Gradle causó una 1.7kdiferencia en los recuentos de métodos referenciados.

Y App Gradle es

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation project(path: ':module')
}

La principal preocupación es ¿por qué la adición del recuento de métodos referenciados individualmente es diferente del recuento total de métodos referenciados en Apk Analyzer?

Esto es solo un filtro IDE, nada más. seguro, si solo selecciona un .dexarchivo, el método de referencia cuenta es igual a la SUMA de cada fila del método de referencia cuenta, pero si selecciona varios .dexarchivos, verá la diferencia en SUMA y el conteo real debido a la igualdad en las referencias que el analizador prefirió filtrarlos

en sus capturas de pantalla seleccionó varios .dexarchivos y luego la igualdad de filtro del analizador.

en nuestro proyecto estamos usando un archivo centralizado dependencies.gradle, por lo que no hay posibilidad de una versión diferente. Entonces, ¿cree que incluso si tenemos el mismo / exacto conjunto de dependencias y sus versiones en módulos de características, aumentará el recuento de métodos referenciados?

Teóricamente NO debería aumentar los recuentos de métodos referenciados. PERO , como lo expliqué, Developer Experience tiene un gran impacto en el resultado final.

Team Analyzer debe verificar y corregir los problemas de rendimiento antes del lanzamiento como

  • reglas de vigilancia
  • recursos reducidos y minificados
  • androidManifest.xml
  • ajustes de gradle

Ahora quiero aclarar cómo la experiencia del desarrollador y el mantenimiento del código afectan el resultado final. INCLUSO si su APK utiliza dependencias centralizadas

figura 3

en el ejemplo anterior, he aumentado 5.1ken el recuento de métodos referenciados ¡¡¡ INCLUSO SI tuviera dependencias centralizadas !!!!!

Como es posible ?

La respuesta es: acabo de agregar un .jararchivo inútil y oculto en el libsdirectorio del proyecto. tan fácil como puedes ver, afecté el resultado final.

Como puede ver, la experiencia del desarrollador afecta el resultado final. Como resultado, prácticamente es posible que los métodos referenciados aumenten aunque, en teoría, NO deberían .

¿Y por qué no hay diferencia en el recuento de métodos referenciados cuando compilo solo el módulo 'aplicación' desactivando la compilación paralela? Debería haber disminuido ya que solo se habrían utilizado las dependencias del módulo 'app', ¿verdad?

La compilación no tiene ninguna relación con los métodos referenciados. Cumple con lo que el desarrollador quiere cumplir.


Conclusión

He cubierto todas las posibilidades en torno al tema. De hecho, puede surgir de diferentes situaciones y un desarrollador al usar esta guía puede solucionar el problema.

  • Espero que haya encontrado por qué los métodos de referencia aumentaron y por qué en algunos casos podría aumentar drásticamente.
  • Los módulos tienen sus módulos de aumento de Gradle & Dependencies y modularización. por lo tanto, estas referencias a métodos.
  • La modularización en realidad impacta el rendimiento de la aplicación ignorable pero hace que el mantenimiento de su aplicación sea mucho mejor.
  • La experiencia del desarrollador en modularización también tiene un gran impacto en el resultado final.

NOTA IMPORTANTE: casi todas las declaraciones son mi investigación e investigaciones. de hecho, puede haber errores y fallas y se actualizarán para agregar mucha más información en el futuro.


Mr.AF
fuente
Gracias, Sr. AF, esperaba obtener la respuesta después de "Esta pregunta me viene a la mente de que los Métodos referenciados cuentan lo que se relaciona con la Profundidad de la herencia. La respuesta es", pero usted no respondió eso. ¿Puede explicar por qué la profundidad de la herencia aumenta el recuento de métodos referenciados? Como en nuestro caso, no hemos agregado ninguna capa adicional, solo dividimos el módulo 'aplicación'. Existe la posibilidad de un aumento en el recuento de métodos referenciados en caso de que un módulo de funciones acceda a métodos de otro módulo de funciones a través del módulo 'aplicación', ¿es esta la razón?
Rohit Surwase
La respuesta de @RohitSurwase es el resto de la declaración. La profundidad de la herencia no aumenta las referencias de métodos, la modularización que hace eso y la modularización porque la profundidad de la herencia.
Mr.AF
@RohitSurwase, una función que accede a otra función en otro módulo en realidad no aumenta mucho los métodos referenciados. La razón principal para aumentar el recuento de métodos referenciados es Gradle y sus dependencias que necesita cada módulo.
Mr.AF
@RohitSurwase señala buenos consejos sobre la relación módulo a módulo. De hecho, si 2 módulos tienen demasiadas relaciones y métodos referenciados, entonces deben combinarse para un mejor rendimiento. En realidad, el módulo debe ser independiente en términos y conceptos.
Sr. AF
1
@RohitSurwase como dije, el jar no utilizado podría no ser su caso. Algo que quiero decir es la experiencia del desarrollador y es posible, la posibilidad puede surgir de diferentes fuentes. y enumeré todas las fuentes posibles que necesita para buscarlo
Mr.AF
2

Respondiendo a mi propia pregunta como la solución simplemente hizo clic en mi mente, aunque esto no se ha intentado pero funcionaría, definitivamente o muy probablemente. :) La respuesta dada por Mr.AF fue muy útil para llegar a una solución final. Habla de ¿Por qué? pero no cómo evitarlo o cómo mejorarlo.

Aquí hay una manera de recuperar el recuento de método referenciado original / real :

No depende de cómo modularizamos la aplicación, sino de cómo agregamos dependencias. Si agregamos una dependencia usando ' implementación ', esa dependencia permanece privada para el módulo y ningún otro módulo puede usarla. Y si agregamos la misma dependencia usando ' api ' (igual a 'compilación' obsoleta), entonces se vuelve pública y otros módulos dependientes pueden usarla. Dado que estamos usando 'implementación' para agregar dependencias en cada módulo en un proyecto de varios módulos, cada módulo tiene todas las dependencias requeridas como autónomas, esta es la razón por la que se puede compilar individualmente. Esto da como resultado una disminución del tiempo de compilación / compilación, ya que solo se pueden compilar módulos modificados. Pero, el uso de 'implementación' aumenta el recuento de métodos referenciados ya que hay muchos métodos duplicados referenciados.

Entonces, si el tiempo de compilación no es su preocupación, pero el recuento de métodos referenciados sí lo es, puede dibujar el árbol de dependencias de todos los módulos y evitar agregar dependencias duplicadas usando 'api' en el módulo base. De esta manera, incluso el módulo superior puede usar la dependencia agregada por el módulo base, lo que evitará duplicados. Recuerde, esto aumentaría el tiempo de construcción.

Podemos lograr ambos si pudiéramos distinguir las dependencias para la depuración y la compilación de la versión . Agregue todas las dependencias utilizando 'implementación' para la compilación de depuración y agregue solo las dependencias necesarias y optimizadas para la compilación de lanzamiento utilizando 'api' . De esta forma, la compilación de depuración será más rápida y la compilación de lanzamiento será más lenta, lo que es asequible.

Nota: Actualizaría esta respuesta una vez que descubra cómo proporcionar dependencias separadas para la depuración y la versión de compilación.

Rohit Surwase
fuente
me gustó buenos materiales.
Mr.AF
0

Veo toda la diferencia en su paquete 'com'. Puede ampliar y comparar qué clases exactas se redujeron. Si compila con el último R8, puede eliminar parte del código por defecto. Cuando coloca algunas clases en el módulo de reducción, no sabe si las clases / métodos públicos se pueden eliminar o si deben permanecer para su uso en otro módulo. ingrese la descripción de la imagen aquí

Dmitry Samoylenko
fuente
Sí, amplié y verifiqué cada paquete, incluido 'com'. La principal preocupación es ¿por qué la adición del recuento de métodos referenciados individualmente es diferente del recuento total de métodos referenciados en Apk Analyzer?
Rohit Surwase