简体   繁体   中英

Referenced Method Count Increased After App Modularization

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

We observed a drastic increase in the number of methods referenced in our app after splitting the 'app' module into several small modules. But the strange thing is that the addition of referenced methods by each class is less than the mentioned total in Android Apk Analyzer Tool.

For test purpose, I have moved WebActivity.class from 'app' module to 'adapters' module and referenced method count increased by 181 methods.

To Summarize:

app/WebActivity = 63546 Actual referenced methods but showing 65394 methods. adapter/WebActivity = 63543 Actual referenced methods but showing 65575 methods.

We have observed 'referenced method count' increased by almost 10k after adding/splitting 4 new modules.

What is the exact issue?

How app modularization can increase the referenced method count drastically so high?

Following are the screenshots I took of two different APKs-only difference is WebActivity moved from 'app' module to 'adapter' module and 181 referenced methods increased:

WebActivity in 'app' module 在此处输入图片说明

Moved WebActivity to 'adapter' module在此处输入图片说明

In the screenshots, why the addition of referenced methods by each class (marked in red color) is not equal to the total given in Apk Analyzer?

I've been reading about code performance and tuning parameters for a long time.Indeed,Android programs are one of my focuses.

Let's intro at first the basic or most important concepts in which help us to reach a solution.

As Android Developer Has stated

module can be independently built, tested, and debugged

Therefore, Modules have their own Gradle & Dependencies .And you can explore it in project Hierarchy Viewer .

As a matter of fact, Modularization emphasis on Maintenance matters. Unlike to Performance Matters.Because, Modularization has this important impact:

  • Increase Depth of inheritance

Here is a diagram that I did plot it to make it clear. As you can see.while using discrete module, in order to invoke Method A there is 2N micro secs compared to N micro secs without discrete module.

在此处输入图片说明

This question my come to your mind that Referenced Methods counts what related to Depth of inheritance?

The answer is : Although using modularization increases Referenced Methods.but, it doesn't actually affect the app performance and the main possible issue is Depth of inheritance in which in most cases is ignorable .

I do emphasis that increased Referenced Methods in modularization is due each Module Gradle & Dependencies

How app modularization can increase the referenced method count drastically so high?

Conditions in which impact APK analyzer importantly Referenced Methods

Also note that minification and code shrinking can each also considerably change the contents of a DEX file after source code is compiled.

In addition to above official statement, I want to add another condition in which impact APK analyzer that's:

how much is the developer experienced in modularization?

modularization is like a home that architecture(developer) define where should be kitchen and where should be rest room and where should be WC. What if the architecture decide to combine WC & Kitchen? Yea this a disaster.

This may happen while modularization if developer be not very much experienced.


Answering to OP questions in Addition to extra information

Here i answer to op asked questions in the comments

Why would separate Gradle add to the referenced method count? And for separate dependency, if the final result is single APK then I do not think duplicate dependencies in 'app' and feature module would add to referenced method count.

Because modules can be built,tested and debugged then they MUST have their own Gradle & Dependencies.

While multi-module project is being complied , compiler generates several .dex files including:

  • a .dex file for total-integrated dependencies
  • modules .dex s

dependencies .dex file is an integrate of all the modules gradles

Let's look at how a module gradle impacts final Referenced Mothods Count?!

there are 2 APK s with same result but difference in Referenced Methods counts.

图1 图2

They are both empty activities that have 1.7k difference in Referenced Methods Count that is very high depend on their functionality. They Key difference is on their Module's Gradle one of them was configured to

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

Another one configured to

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

Although they are just empty activities but a minimal difference in Gradle caused 1.7k difference in Referenced Method Counts.

And App Gradle is

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')
}

major concern is why addition of individually referenced method count is different than total referenced method count in Apk Analyzer?

This is just IDE filter nothing else. for sure , if you only select a .dex file Reference Method Counts is equal to SUM of the each row Referenced Method Counts but if you multi-select .dex files , You will see difference in SUM and actual Count that because of equality in References that Analyzer preferred to filter them.

in your screenshots you've selected multiple .dex files then Analyzer filter equality.

in our project we are using centralized dependencies.gradle file so there is not chance of different version. So, do you think even if we have same/exact set of dependencies and their versions in feature modules, it will increase referenced method count?

Theoretically it should NOT increase referenced method counts. BUT , As i explained it , Developer Experience highly impacts final result.

Team Analyzer should check and fix performance issues before release like

  • proguard rules
  • shrunk & minified resources
  • androidManifest.xml
  • gradle settings

Now i want to clarify it how Developer Experience and code maintenance affects final result. EVEN if your APK uses Centralized Dependencies

图3

in the above example, i'v increased 5.1k in Referenced Methods Count EVEN IF i had Centralized Dependencies !!!!!

How it's possible ?

The answer is : i just added a useless and hidden .jar file in libs directory of project. just as easy as you can see i affected the final result.

As you can see Developer Experience affects final result.as a result, Practically it's possible that referenced methods counts to be increased Although Theoretically Should NOT .

And why there is no difference in referenced method count when I compile only 'app' module by disabling parallel compilation? It should have decreased as only 'app' module's dependencies would have been used, right?

compilation has not any relation to referenced methods counts.it complies what developer wants to complied.


Conclusion

I have covered all the possibilities around the issue. Indeed, it can be emerged from different situations and a developer by using this guideline can fix the issue.

  • I would hope that you found why Referenced Methods was increased and why in some cases it might be drastically increased.
  • Modules has their Gradle & Dependencies and modularization increase modules. therefore, these Method References.
  • Modularization actually impact app performance ignorable but makes your app Maintenance highly better.
  • Developer experience in modularization also highly impacts the final result.

IMPORTANT NOTE: almost all of the statements are my investigation & researches. indeed, there may be errors and faults and will be updated in order to add much more information in future.


Answering my own question as the solution just clicked in my mind, though this is not tried but would work, definitely or most probably. :) The answer given by Mr.AF was very useful to reach a final solution. It talks about Why? but not how to avoid it or how to improve upon that.

Here is a way to get back the original/actual referenced method count -

It is not dependent on how we modularise the app but on how we add dependencies. If we add a dependency using ' implementation ' then that dependency remains private to the module and no other module can use it. And if we add the same dependency using ' api ' (equal to deprecated 'compile') then it becomes public and other dependent modules can use it. Since we are using 'implementation' to add dependencies in each module in a multi-module project, each module has all required dependencies as self-contained, this is the reason it can be compiled individually. This results in decreased build/compile time as only modified modules can be compiled. But, use of 'implementation' increases the referenced method count as there are so many duplicate referenced methods.

So, if build time is not your concern but referenced method count is then you can draw the dependency tree of all modules and avoid adding duplicate dependency by using 'api' in the base module. This way even top module can use dependency added by the base module which will avoid duplicates. Remember, this would increase the build time.

We can achieve both if we could distinguish dependencies for debug and release build . Add all dependencies using 'implementation' for debug build and add only required and optimized dependencies for release build by using 'api' . This way debug build will be faster and release build will be slower which is affordable.

Note: I would update this answer once I figure out how to provide separate dependencies for debug and release build.

I see all the difference in your 'com' package. You can expand and compare what exact classes were shrinked. If you build with latest R8 it can remove some code by default. When you put some classes into module shrinker don't know if public classes/methods can be removed or must stay for use in another module. 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM