Lambda expressions in Android (part 2/2)

In the previous post, lambda expressions in Java 8 have been introduced. In this post I will describe how to enable and use Java 8 language features including lambda expressions in Android development.

Until recently, only Java 7 was officially supported when developing for Android. However, this changes with the release of Android N (Nougat, API version 24) and its official support for Java 8. Before Android N was released however, it was also possible to use an external library called retrolambda which allows to bring lambda expressions support to Java 7 and lower.

Android N & Jack toolchain

With the release of Android N, a new toolchain Jack has been published too. Jack toolchain comprises a compiler from Java source to the Android dex file format. Among the features Jack provides are: repackaging, shrinking, obfuscation, multidex and Java 8 support.

Before we begin, first of all, make sure you have Java 8 JDK installed on your system and that you’re running Android Studio 2.1 or higher. Also, you need to set a correct path to JDK installation folder in Android Studio in order to use all the new Java 8 features. In Android Studio go to the main menu File -> Project Structure… and input the path to Java 8 JDK (in my case /usr/lib/jvm/java-1.8.0-openjdk-amd64) like this:

Android Studio JDK location (for setting up the lambda expressions in Android)

In order to let your IDE know that you’re using Java 8 features in your source code, add the compileOptions section to build.gradle. As Jack toolchain is still an experimental tool, it needs to be explicitly enabled in the module-level build.gradle file too:

android {
    ...
    defaultConfig {
      ...
      jackOptions {
        enabled true
      }
    }
    compileOptions {
      sourceCompatibility JavaVersion.VERSION_1_8
      targetCompatibility JavaVersion.VERSION_1_8
    }
}

After this, try to compile and run a simple example of setting an OnClickListener on a Button:
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = (Button) findViewById(R.id.button);
        if (button != null) {
            button.setOnClickListener((View view) -> Toast.makeText(this, 
                "Button pressed!", Toast.LENGTH_LONG).show());
        }
    }
}

If everything went well, you have successfully set up using Java 8 features including lambda expressions in Android.

Java 8 supported language features

The Android support of Java 8 language is not complete at the time of writing the post. However, all the main features are supported and some of them (like lambda expressions) are also backported to API level 23 and lower (with Jack compiler enabled). Here’s a list of the supported features:

  • Lambda expressions (also for API <= 23)
  • Method references (also for API <= 23)
  • Type annotations (also for API <= 23)
  • Default and static interface methods
  • Repeatable annotations

Other than the listed, it’s worth mentioning that Stream API is also supported as well as some other features (for a full list, please refer to the official documentation).

Retrolambda

Before Java 8 was officially supported in Android, the only way how to use Java 8 language features, specifically lambda expressions, was to use an external library like retrolambda [link] together with gradle-retrolambda [link]. Even now, when Java 8 is officially supported, there might be cases when you need to use the library instead.

The author explains how retrolambda works on his GitHub page:

Retrolambda lets you run Java 8 code with lambda expressions, method references and try-with-resources statements on Java 7, 6 or 5. It does this by transforming your Java 8 compiled bytecode so that it can run on an older Java runtime. After the transformation they are just a bunch of normal .class files, without any additional runtime dependencies.

To set up retrolambda in Android Studio, follow these steps. Again, you will need to set the path to Java 8 JDK in Android Studio. Then, in the project-level build.gradle file, add the following lines so that it looks like this:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'me.tatarka:gradle-retrolambda:3.2.5'
    }
}
...

The module-level build.gradle file should contain following:
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.1"

    defaultConfig {
        applicationId "com.example.lambdas"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

After that, you should be all set to use lambda expressions in Android and Java version lower than 8.

Conclusion

In this post, two ways of enabling the usage of Java 8 language features including lambda expressions in Android development have been presented (see my post on lambda expression in Java 8 too). First, the official Java 8 support that comes with Android N and Jack toolchain and the second, provided by an external libraries retrolambda and gradle-retrolambda.

Sources

Share this: