Getting Started With JRebel for Android
A tutorial on how to use JRebel to squeeze the most out of your Gradle builds for Android apps.
Join the DZone community and get the full member experience.Join For Free
Android development is great as long as your project stays relatively small. As the functionality of your project grows you’ll find that your build times follow suit. This puts you in the position where you spend most of your time figuring how to make your build run faster rather than adding more value to your actual app.
The interwebs are packed full with suggestions of how to squeeze the most out of your Gradle builds. There are some great posts on this, including, “Making Gradle builds faster”. Although you can win back seconds and maybe even minutes, some bottlenecks will still remain in your build. For example, having annotation-based dependency injections are nice to have for a cleaner architecture, but it has an impact on your build time.
One thing you can try is JRebel for Android. It takes a different approach by not introducing a new apk after each change. Instead, the APK gets installed once and delta packages are shipped over to the device or emulator and are applied during runtime. This logic is nothing new and has been present in the Java EE/SE and JRebel for more than 8 years.
Let’s take the Google IO 2015 app and see how the JRebel for Android setup works as well as how it can save you valuable time.
Installing JRebel for Android
JRebel for Android is available as a plugin for Android Studio. You can download it directly from the IDE by navigating to Plugins > Browse Repositories and searching for “JRebel for Android”.
If for some reason you can’t access the public maven repositories you can download it directly from the JetBrains homepage. After which you need to install via the Plugins > Install plugin from disk… route.
Once the plugin is installed, you’ll need to restart Android Studio, as usual after a plugin installation. After restart, you need to provide your name and email to get your free 21 day trial of JRebel for Android.
Running My Application With JRebel for Android
Now the plugin is installed, you just need to click the Run with JRebel for Android button, which will always build a new apk if changes are detected between the previous installation. Run with JRebel for Android is the same as the Run action in Android Studio. So you’ll be faced with the same run flow, where you first need to pick a device and then apk is built and installed on that device etc.
To update your code and resources, JRebel for Android needs to process the project’s classes and embed an agent to the application. JRebel for Android will only run with a debuggable flavor, so your release apk is never affected. In addition no changes are required to your project. For a detailed overview of how JRebel for Android works, read this under the hood post.
So pressing Run with JRebel for Android on the Google IO 2015 application would result in the following:
Applying Changes With JRebel for Android
The Apply changes button is the key when using JRebel for Android, it will do the least amount of work possible to make your changes and updates visible on your device. If you didn’t use Run with JRebel for Android to install the application yet, Apply changes will take care of the installation on your behalf.
Now let’s make a simple functional change to the application. For each session taking place in GoogleIO you can send feedback. We’ll add one additional element to the question, an input for your name and we’ll use the value from that input in a Toast thanking you for providing feedback.
Step 1: Add an EditText component to the session_feedback_fragment.xml
<FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/name_input" android:layout_width="match_parent" android:layout_height="wrap_content"/> </FrameLayout>
Step 2: Fix the paddings
<FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="@dimen/padding_normal" android:paddingStart="@dimen/padding_normal" android:paddingRight="@dimen/padding_normal" android:paddingEnd="@dimen/padding_normal" android:paddingTop="@dimen/spacing_micro" android:paddingBottom="@dimen/padding_normal">
Step 3: Add a hint
<EditText android:id="@+id/name_input" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/name_hint"/>
During all of these changes we have remained on the same screen on our device throughout. After each Apply change Activity.recreate() is invoked by JRebel for Android. So your topmost activity will go through the same callbacks as you would if you rotated your device from portrait to landscape, for example.
So far we’ve only performed resource changes, so let’s change some Java code as well.
Step 4: Show a toast in SessionFeedbackFragment.sumbitFeedback()
EditText nameInput = (EditText) getView().findViewById(R.id.name_input); Toast.makeText(getActivity(), "Thanks for the feedback " + nameInput.getEditableText().toString(), Toast.LENGTH_SHORT).show();
If reading isn't believing, here is a short JRebel for Android in action video:
Application Restart vs. Activity Restart
Not all changes will trigger an Activity.recreate() invocation. Should you change something in the AndroidManifest, a new APK has to be built and an incremental install will be performed. In this case the application will be restarted. An application restart will also be done if you replace a superclass or change interfaces that the class is implementing. Here is a full breakdown of activity vs. application restart:
|Activity restart||Application restart|
Adding, removing, modifying methods
Adding, removing implemented interfaces
Adding, removing, modifying constructors
Adding, removing fields
Adding, removing classes
Adding, removing annotations
Adding, removing, modifying static fields value
Adding, removing enum values
Adding, removing, modifying XML resources
Opinions expressed by DZone contributors are their own.