- Android Studio Project Marble: Apply Changes
- A deep dive into how the Android Studio team built Apply Changes, the successor to Instant Run.
- Instant Run
- Apply Changes
- Principles
- Architecture
- Android Studio 3.5 Canary adds “Apply Changes,” an Instant Run replacement
- Apply Changes lets you push code and resource changes to your running app without restarting your app—and, in some cases, without restarting the current activity. Apply Changes replaces Instant Run with a completely new approach for build optimization. Instead of rewriting the bytecode of your APK during build time, Apply Changes redefines classes on the fly by leveraging the runtime instrumentation supported in Android 8.0 (API level 26) or higher.
- In addition, Android Studio now prompts you to decide whether to restart your app or activity when it detects that changes are not compatible with Apply Changes. This extra control should provide you with a more consistent and predictable experience compared to the behavior of Instant Run.
- It does something very, very different. Instant Run had a very specific impact on build, instrumenting each of your classes at compile time to prepare them for being replaced during the runtime with a new version of the class. It also split your APK in several APKs to re-upload your app more incrementally.
- Apply Changes does nothing like it. Your APK is very much the same whether you use Apply Changes or not. Instead it relies on new runtime instrumentation capabilities of the ART VM to dynamic reload classes and replace them while the app is running. This is why it requires much newer versions of Android.
- Build and run your app
- Change the run/debug configuration
- Change the build variant
- Build your project
- Monitor the build process
- Apply Changes
- Requirements
- Use Apply Changes
- Enable Run fallback for Apply Changes
- Platform-dependent changes
- Limitations of Apply Changes
- Code changes that require app restart
- Libraries and plugins
- Code that directly references content in an installed APK
Android Studio Project Marble: Apply Changes
A deep dive into how the Android Studio team built Apply Changes, the successor to Instant Run.
This is the first in a series of blog posts by the Android Studio team diving into some of the details and behind the scenes of Project Marble . Beginning with the release of Android Studio 3.3 , Project Marble is a multi-release and focused effort on making fundamental features of the IDE rock-solid and polished. The following post was written by Jon Tsao (product manager), Esteban de la Canal (tech lead), Fabien Sanglard (engineer), and Alan Leung (engineer) on the Apply Changes team.
A key goal for Android Studio is to provide tools that allow you to quickly edit and validate code changes in your app. When we created Instant Run, we wanted to dramatically accelerate your development flow, but we know that the feature fell short of those expectations. As a part of Project Marble, we’ve been working on rethinking Instant Run, and are replacing it in Android Studio with a more practical solution called Apply Changes. Initially previewed in the canary channel of Android Studio 3.5, Apply Changes is the new way to predictably accelerate your development workflow. In this post, we want to give a little more insight into the feature, how it works, and our journey so far.
Instant Run
With Instant Run, we wanted to solve two issues: 1) decrease the build and deploy speed to your device and 2) enable the ability to deploy changes to your app without losing state. To achieve this in Instant Run, we relied on rewriting your APKs at build time to inject hooks that allow class replacement on-the-fly. For a more detailed look at the architecture behind Instant Run, see this Medium post from a few years back.
For simple apps, this solution was usually fine, but for more complex apps, this could result in longer build times or head-scratching errors caused by conflicts between your app and Instant Run’s build process. As these issues came up, we continued to invest in improving Instant Run over subsequent releases. However, we were never able to fully resolve these issues and bring the feature in line with our expectations.
We took a step back and decided to build a new architecture from the ground up, which became Apply Changes. Unlike Instant Run, Apply Changes no longer modifies your APK during builds. Instead, we rely on runtime instrumentation that is supported in Android 8.0 (Oreo) and newer devices and emulators to redefine classes on the fly.
Apply Changes
For devices and emulators running on Android 8.0 or newer, Android Studio now features three buttons that control how much of the application is restarted:
- Run will continue to deploy all changes and restart the application.
- Apply Changes will attempt to apply your resource and code changes and restart only your activity without restarting your app.
- Apply Code Changes will attempt to apply only your code changes without restarting anything.
Compatible code changes are generally limited to code that has changed within method bodies.
Principles
Based on the experiences and feedback from Instant Run, we adopted a few principles for Apply Changes that guided our architecture and decision-making:
- Separating build/deploy speed and losing state. We wanted to separate the two concerns of decreasing build/deploy speed from being able to see your changes without losing state. Fast builds and deploys should be a goal for all types of deploys, regardless of whether it’s a regular run/debug session or a hot swap of code. As part of building Apply Changes, we’ve found quite a few areas that we’ve optimized around build and deploy speed that we will detail in future posts.
- Stability of the feature is paramount. Even if the feature works 99 out of 100 times at blazing fast speeds, if the app crashes once because of the feature and you spend half an hour trying to figure out why, you’ve lost the productivity gains from the other 99 times where it worked. As a result of us adhering to this principle, Apply Changes, unlike Instant Run, no longer modifies your APK during builds. One byproduct of that is that in this initial version where we’ve optimized for stability, Apply Changes is slightly slower than Instant Run on average, but we’re continuing to improve build and deploy speeds going forward.
- No magic. We incorporated your feedback around the unpredictability and inconsistencies in behavior of the Instant Run button that would automatically decide whether or not to restart your app or activity if necessary. We wanted to be clear and transparent at all times as far as what you should expect out of Apply Changes and what happens if you have an incompatible change, so we now explicitly prompt you if we detect that your change is not compatible with Apply Changes.
Architecture
Let’s dive into how Apply Changes works. Apply Changes needs to figure out how to apply the differences between the application that is installed / running on the device and the application that was just compiled in Android Studio. This process can be split into two different steps: 1) figure out what the difference is, and 2) send that difference to the device and apply it.
To determine the difference quickly, Apply Changes avoids fetching the full APK from the device. Instead, it executes a quick request to the device to pull the installed APK’s corresponding table of contents, and signature. By comparing these two pieces of information against the newly built APK, Apply Changes efficiently generates a list of changed files since the last deployment without having to examine the full contents. Note that this algorithm does not depend on the build system, as the delta is not computed against the previous build, but against what is installed on device. Since Apply Changes operates solely on differences between APK files, it does not require the Gradle plug-in versions to be in sync with Gradle. In fact, Apply Changes will work on all build systems.
After the list of files that has changed is produced, depending on what has changed, there are different actions that need to be performed to apply these changes to the running app, and this also determines how far back the app needs to be restarted for these changes to take effect:
Resource/asset files have changed.
In this case the application is reinstalled, but the application only goes through an activity restart and the modified resources are picked up. Only the changed resources are sent to the device.
.dex files have changed.
The Android Runtime as of Android 8.0 offers the ability to swap bytecode of loaded classes, as long as the new bytecode does not alter the existing object layout in memory. This implies limitations on what code changes are compatible with Apply Changes: that method and class names and signatures do not change and neither do their fields.
This mechanism works at the class level and not at .dex level. Otherwise, if a .dex file contains hundreds or thousands of classes, it would be inefficient to attempt to swap all of the classes, even if only one has changed. Instead we compare the content of the .dex and compute the exact classes that have changed and only attempt to swap those. If the swap is successful (i.e. the class layout has not changed), then the app is also installed in the background to avoid inconsistencies between the running and installed versions of the app.
.dex files and resources files have changed.
This case is a combination of the two cases above. First the code step is executed and, if it is successful, the installation proceeds with the new resources. The main Activity will need to be restarted for the new resources to be loaded. This is an all-or-nothing operation where if your code changes cannot be applied, nothing will be changed on the running app.
Источник
Android Studio 3.5 Canary adds “Apply Changes,” an Instant Run replacement
Android Studio 3.5 (currently in the Canary and Dev channels) now features a new way to push code changes to your app and see their effects on the fly without having to restart the app. Dubbed simply “Apply Changes,” it’s the successor to the “Instant Run” feature in previous versions of Android Studio.
Google’s Android Developers Blog says the following about Apply Changes:
Apply Changes lets you push code and resource changes to your running app without restarting your app—and, in some cases, without restarting the current activity. Apply Changes replaces Instant Run with a completely new approach for build optimization. Instead of rewriting the bytecode of your APK during build time, Apply Changes redefines classes on the fly by leveraging the runtime instrumentation supported in Android 8.0 (API level 26) or higher.
In addition, Android Studio now prompts you to decide whether to restart your app or activity when it detects that changes are not compatible with Apply Changes. This extra control should provide you with a more consistent and predictable experience compared to the behavior of Instant Run.
The blog post goes on to list some limitations to the new functionality. For example, the device you’re testing your app on must at least be running Android 8.0 Oreo (API Level 26) and there are certain code changes that will still require your app to restart. As with “Instant Run,” “Apply Changes” will force your app to restart if you’re:
- Adding or deleting a class, method, or field
- Changing the manifest
- Changing method signatures
- Changing modifiers of methods or classes
- Renaming classes
- Changing class inheritance
- Adding or removing a resource
Under “Known Issues,” the blog post states that since Google initially prioritized stability over performance in this new feature, “Apply Changes” will sometimes run more slowly than its forebear feature “Instant Run.” Also, x86_x64 emulator images are not supported, and for debugging purposes, only Android Pie (API Level 28) is supported. You can see the full list of limitations and known issues at the source link below.
For a more detailed description of the difference between “Apply Changes” and “Instant Run,” a Google employee on the Android Studio team had this to say on Reddit:
It does something very, very different. Instant Run had a very specific impact on build, instrumenting each of your classes at compile time to prepare them for being replaced during the runtime with a new version of the class. It also split your APK in several APKs to re-upload your app more incrementally.
Apply Changes does nothing like it. Your APK is very much the same whether you use Apply Changes or not. Instead it relies on new runtime instrumentation capabilities of the ART VM to dynamic reload classes and replace them while the app is running. This is why it requires much newer versions of Android.
“Apply Changes” is expected to eventually replace “Instant Run” in the Beta and Stable channels as Google makes improvements to its performance and stability.
Источник
Build and run your app
Android Studio sets up new projects to deploy to the Android Emulator or a connected device with just a few clicks. Once your app is installed, you can use Apply Changes to deploy certain code and resource changes without building a new APK.
To build and run your app, follow these steps:
- In the toolbar, select your app from the run configurations drop-down menu.
From the target device drop-down menu, select the device that you want to run your app on.
If you don’t have any devices configured, then you need to either connect a device via USB or create an AVD to use the Android Emulator.
Click Run .
Change the run/debug configuration
When you run your app for the first time, Android Studio uses a default run configuration. The run configuration specifies whether to deploy your app from an APK or an Android App Bundle, the module to run, package to deploy, activity to start, target device, emulator settings, logcat options, and more.
The default run/debug configuration builds an APK, launches the default project activity, and uses the Select Deployment Target dialog for target device selection. If the default settings don’t suit your project or module, you can customize the run/debug configuration, or even create a new one, at the project, default, and module levels. To edit a run/debug configuration, select Run > Edit Configurations. For more information, see Create and Edit Run/Debug Configurations.
Change the build variant
By default, Android Studio builds the debug version of your app, which is intended for use only during development, when you click Run.
To change the build variant Android Studio uses, select Build > Select Build Variant in the menu bar.
For projects without native/C++ code, the Build Variants panel has two columns: Module and Active Build Variant. The Active Build Variant value for the module determines which build variant the IDE deploys to your connected device and is visible in the editor.
Figure 1. The Build Variants panel has two columns for projects that do not have native/C++ code
To switch between variants, click the Active Build Variant cell for a module and choose the desired variant from the list field.
For projects with native/C++ code, the Build Variants panel has three columns: Module, Active Build Variant, and Active ABI. The Active Build Variant value for the module determines the build variant that the IDE deploys to your device and is visible in the editor. For native modules, the Active ABI value determines the ABI that the editor uses, but does not impact what is deployed.
Figure 2. The Build Variants panel adds the Active ABI column for projects with native/C++ code
To change the build variant or ABI, click the cell for the Active Build Variant or Active ABI column and choose the desired variant or ABI from the list. After you change the selection, the IDE syncs your project automatically. Changing either column for an app or library module will apply the change to all dependent rows.
By default, new projects are set up with two build variants: a debug and release variant. You need to build the release variant to prepare your app for public release.
To build other variations of your app, each with different features or device requirements, you can define additional build variants.
Conflicts in Android Studio’s Build Variants dialog
In Android Studio’s Build Variants dialog, you might see error messages indicating conflicts between build variants, such as the following:
This error does not indicate a build issue with Gradle – it is only indicating that the Android Studio IDE itself cannot resolve symbols between the variants of the selected modules.
For example, if you have a module M1 that depends on variant v1 of module M2 , but M2 has variant v2 selected in the IDE, you have unresolved symbols in the IDE. Let’s say that M1 depends on a class Foo which is only available in v1 . When v2 is selected, that class is not known by the IDE and it will fail to resolve it and show errors in the code of M1 .
These error messages appear because the IDE cannot load code for multiple variants simultaneously. In terms of your app’s build, however, the variant selected in this dialog will have no effect because Gradle builds your app with the source code specified in your Gradle build recipes, not based on what’s currently loaded in the IDE.
Build your project
The Run button builds and deploys your app to a device. However, to build your app to share or upload to Google Play, you’ll need to use one of the options in the Build menu to compile parts or all of your project. Before you select any of the build options listed in table 1, make sure you first select the build variant you want to use.
Table 1. Build options in the Build menu.
Menu Item | Description |
---|---|
Make Module | Compiles all source files in the selected module that have been modified since the last build, and all modules the selected module depends on recursively. The compilation includes dependent source files and any associated build tasks. You can select the module to build by selecting either the module name or one of its files in the Project window. |
Make Project | Makes all modules. |
Clean Project | Deletes all intermediate/cached build files. |
Rebuild Project | Runs Clean Project for the selected build variant and produces an APK. |
Build Bundle(s) / APK(s) > Build APK(s) | |
Build Bundle(s) / APK(s) > Build Bundle(s) | |
Brings up a dialog with a wizard to set up a new signing configuration, and build either a signed app bundle or APK. You need to sign your app with a release key before you can upload it to the Play Console. For more information about app signing, see Sign your app. |
Note: The Run button builds an APK with testOnly=»true» , which means the APK can only be installed via adb (which Android Studio uses). If you want a debuggable APK that people can install without adb, select your debug variant and click Build Bundle(s) / APK(s) > Build APK(s).
For details about the tasks that Gradle executes for each command, open the Build window as described in the next section. For more information about Gradle and the build process, see Configure Your Build.
Monitor the build process
You can view details about the build process by clicking View > Tool Windows > Build (or by clicking Build in the tool window bar). The window displays the tasks that Gradle executes in order to build your app, as shown in figure 3.
Figure 3. The Build output window in Android Studio
- Build tab: Displays the tasks Gradle executes as a tree, where each node represents either a build phase or a group of task dependencies. If you receive build-time or compile-time errors, inspect the tree and select an element to read the error output, as shown in figure 4.
Figure 4. Inspect the Build output window for error messages
If your build variants use product flavors, Gradle also invokes tasks to build those product flavors. To view the list of all available build tasks, click View > Tool Windows > Gradle (or click Gradle in the tool window bar).
If an error occurs during the build process, Gradle may recommend some command-line options to help you resolve the issue, such as —stacktrace or —debug . To use command-line options with your build process:
- Open the Settings or Preferences dialog:
- On Windows or Linux, select File >Settings from the menu bar.
- On Mac OSX, select Android Studio >Preferences from the menu bar.
- Navigate to Build, Execution, Deployment >Compiler.
- In the text field next to Command-line Options, enter your command-line options.
- Click OK to save and exit.
Gradle applies these command-line options the next time you try building your app.
Apply Changes
In Android Studio 3.5 and higher, Apply Changes lets you push code and resource changes to your running app without restarting your app—and, in some cases, without restarting the current activity. This flexibility helps you control how much of your app is restarted when you want to deploy and test small, incremental changes while preserving your device’s current state. Apply Changes uses capabilities in the Android JVMTI implementation that are supported on devices running Android 8.0 (API level 26) or higher. To learn more about how Apply Changes works, see Android Studio Project Marble: Apply Changes.
Requirements
Apply Changes actions are only available when you meet the following conditions:
- You build the APK of your app using a debug build variant.
- You deploy your app to a target device or emulator that runs Android 8.0 (API level 26) or higher.
Use Apply Changes
Use the following options when you want to deploy your changes to a compatible device:
Apply Changes and Restart Activity
Attempts to apply both your resource and code changes by restarting your activity but without restarting your app. Generally, you can use this option when you’ve modified code in the body of a method or modified an existing resource.
You can also perform this action by pressing Ctrl+Alt+F10 (or Control+Shift+Command+R on macOS).
Apply Code Changes
Attempts to apply only your code changes without restarting anything. Generally, you can use this option when you’ve modified code in the body of a method but you have not modified any resources. If you’ve modified both code and resources, use Apply Changes and Restart Activity instead.
You can also perform this action by pressing Ctrl+F10 (or Control+Command+R on macOS).
Run
Deploys all changes and restarts the app. Use this option when the changes that you have made cannot be applied using either of the Apply Changes options. To learn more about the types of changes that require an app restart, see Limitations of Apply Changes.
Enable Run fallback for Apply Changes
After you’ve clicked either Apply Changes and Restart Activity or Apply Code Changes, Android Studio builds a new APK and determines whether the changes can be applied. If the changes can’t be applied and would cause Apply Changes to fail, Android Studio prompts you to Run your app again instead. However, if you don’t want to be prompted every time this occurs, you can configure Android Studio to automatically rerun your app when changes can’t be applied.
To enable this behavior, follow these steps:
Open the Settings or Preferences dialog:
- On Windows or Linux, select File > Settings from the menu bar.
- On macOS, select Android Studio > Preferences from the menu bar.
Navigate to Build, Execution, Deployment > Deployment.
Select the checkboxes to enable automatic Run fallback for either of the Apply Changes actions.
Click OK.
Platform-dependent changes
Some features of Apply Changes depend on specific versions of the Android platform. To apply these kinds of changes, your app must be deployed to a device running that version of Android (or higher).
Type of change | Minimum platform version |
---|---|
Adding a method | Android 11 |
Limitations of Apply Changes
Apply Changes is designed to speed up the app deployment process. However, there are some limitations for when it can be used. If you encounter any issues while using Apply Changes, file a bug.
Code changes that require app restart
Some code and resource changes cannot be applied until the app is restarted, including the following:
- Adding or removing a field
- Removing a method
- Changing method signatures
- Changing modifiers of methods or classes
- Changing class inheritance
- Changing values in enums
- Adding or removing a resource
- Changing the app manifest
- Changing native libraries (SO files)
Libraries and plugins
Some libraries and plugins automatically make changes to your app’s manifest files or to resources that are referenced in the manifest. These automatic updates can interfere with Apply Changes in the following ways:
- If a library or plugin makes changes to your app’s manifest, you can’t use either Apply Code Changes or Apply Changes and Restart Activity and have to restart your app before you can see your changes.
- If a library or plugin makes changes to your app’s resource files, you can’t use Apply Code Changes , and you must use Apply Changes and Restart Activity to see your changes.
You can avoid these limitations by disabling all automatic updates for your debug build variants.
For example, Crashlytics updates app resources with a unique build ID during every build, which prevents you from using Apply Code Changes and requires you to restart your app’s activity to see your changes. You can disable this behavior so that you can use Apply Code Changes alongside Crashlytics with your debug builds.
Code that directly references content in an installed APK
If your code directly references content from your app’s APK that’s installed on the device, that code can cause crashes or misbehave after clicking Apply Code Changes . This behavior occurs because when you click Apply Code Changes, the underlying APK on the device is replaced during installation. In these cases, you can click Apply Changes and Restart Activity or Run , instead.
Content and code samples on this page are subject to the licenses described in the Content License. Java is a registered trademark of Oracle and/or its affiliates.
Источник