Hello! This article is a translation of the note by Android developer and author of the book “Android 4. Programming applications for tablet computers and smartphones” by Reto Meier. Over the translation worked Android-department of the company Live Taiping . The original article is available here.
Most people are quite happy when something simple and useful falls into their hands. But we, programmers, do not belong to this majority.
Take, for example, Instant Run. This is a feature of Android Studio, which, with the help of "magic", reduces the time spent on assembly and deploying incremental code changes in the process of writing / testing / debugging.
I call it magic because from the outside it looks that way. After the first press of Run or Debug, everything works as expected. However, every time changes are made to the code and the Run or Debug button is pressed again (but this time with the lightning icon), the changes are applied to my phone so quickly that I don’t have time to notice it.
But let's leave the magic for Sunday TV gatherings.
Personally, I'm more comfortable when magic comes to me, complete with dragons, political intrigues and unexpected plot twists. So I met with a team of engineers who worked on Android Studio to find out how Instant Run actually works.
We start with this simple flowchart of a typical application build cycle.
Build, deploy / install, run the application, run the activation.
The goals pursued by Instant Run are extremely simple: remove as many of these steps as possible and speed up those that remain as a result.
In practice, this means:
· Assembly and deployment only incremental changes;
· Do not reinstall the application;
· Do not restart the application;
· Do not restart the activation.
Instant Run = incremental change build + hot, warm or cold swap.
Hot swap : changes are made to the application without the need to restart it and even without the need to restart the current activation. It can be used for most simple edits within the implementation of methods.
Warm replacement : in order for the edits to take effect, you must restart the activation. Usually required when changing resources.
Cold swap : restart the application (without having to reinstall). Required when making structural changes, such as inheritance or changing method signatures.
When you click Run or Debug, something like this happens:
Manifests are collected in one file, which together with resources and .dex files are packaged in an APK.
Your manifests are collected and packaged along with resources in the APK. Similarly, your .java files are compiled into bytecode, converted into .dex files and sent to the same APK.
The first time you click Run or Debug with Instant Run enabled, Gradle performs several additional tasks.
Java Bytecode Instrumentation and App Server are embedded in your debug APK file.
Bytecode Instrumentation is added to your .class files and the new App Server class is backed up to your application.
In addition, a new class definition is added to the Application class, which injects custom class loaders and starts App Server. In order for your application to be able to use these changes, the Android manifest file is modified. If you created your own Application class, Instant Run will replace it.
Instant Run is now running and tracks all changes you make to the code. So the next time you click on Run or Debug, Instant Run will try to shorten the build process as much as possible using a hot, warm or cold replacement.
Before you apply the changes, Android Studio checks for an open socket in the App Server running inside the application with Instant Run enabled. He confirms that the application is running, and its buildID is the one that expects Android Studio.
Android Studio tracks changes to files during development and runs a special Gradle-Task to generate .dex files for modified classes only. Then, Android Studio picks up these files and deploit them to the App Server that runs inside the application.
Since the original versions of our classes already exist in the running application, Gradle with the help of the Transformation API replaces them with new ones. After that, the modified classes are loaded by App Server using custom class loaders.
From this point on, each time the method is invoked within our application, the special tools implemented in our source classes interact with App Server to see if they have been updated.
If so, the execution is delegated to the new swapped classes, and instead of the old method, its new version is launched.
If you set debugging points, you will see calls to the class method called “override” in the frametrack.
The redirection of methods works well in the case of a change in the implementation of the methods themselves, but what to do with the things that are loaded during the activation start?
Warm replacement restarts activit. Resources are loaded before the launch of the activation. Therefore, any modification of them requires a reboot of the activation for the forced reload of resources.
At the moment, changing any resource causes all resources to be repackaged and sent to your application. But we are working hard on a packer that will pack and deploy only new or changed resources.
Please note that the warm replacement will not work for the resources mentioned in the Android manifest, as well as in case of changes made to the manifest itself, since the values of this file are read during the installation of the APK. Changes affecting the manifest will result in a full cycle of building and installing the application.
Unfortunately, restarting the activation cannot magically apply structural changes. Adding, deleting, or modifying annotations, fields, method signatures, changing parent classes, or static initializations require a cold replacement.
After deploying, your application and its subprojects are divided into several .dex files. Classes are distributed to these files depending on the names of the packages in which they are located. When cold replacing, the .dex file that owns the modified class is fully recompiled along with the other classes that belong to it, and deploys again.
This approach is based on the ability of Android Runtime to download several .dex files (a feature that appeared in ART) and therefore can only be used for devices running Android version 5.0 (API Level 21) and higher.
On devices running API Level 20 or lower, and therefore using DALVIK, Android Studio deploit the entire APK.
Although Instant Run is very smart, but he can’t turn back time. Changes in the code that could be applied by hot swapping, but which affect the initialization run on the first start of the application, will require you to restart the entire application to take effect.
To perform an incremental build and restart the application, press Rerun (CTRL-CMD-r).
Instant Run is controlled by Android Studio, so run / restart your debug-version via IDE - do not do this directly from the device, otherwise your entire work will fly to the cat's tail.
A more detailed list of tips is available in the Android documentation, but here are the most basic points that you should always keep in mind.
Instant Run is constantly evolving, the development team is exploring new techniques to increase the number of cases that allow the use of hot swap and reduce the need for cold replacements or complete reassembly.
Source: https://habr.com/ru/post/304640/
All Articles