Infinum android talks_10_getting groovy on android

Post on 18-Jul-2015

87 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

Transcript

android.talks@infinum.hr

Getting

on AndroidIvan Kušt

Java on Android

• no Java 8 and lambda expressions

• writing a lot of boilerplate code

Groovy

• optionally typed

• dynamic language

• compiles into Java VM bytecode

Groovy

Thread thread = new Thread(new Runnable() { @Override void run() { //do stuff in background } });

• example (executing code in a new thread) on Java:

Groovy

• same thing in Groovy, using closures:

Thread.start { //do stuff in background }

Groovy

• more concise code

• more readable code

• still type safe

• still fast

Benefits of Groovy• semi colons are optional

• parentheses are optional

• dynamic typing

• return keyword is optional

• public keyword is optional

• all Java is valid Groovy

vs

Default imports• java.io.*

• java.lang.*

• java.math.BigDecimal

• java.math.BigInteger

• java.net.*

• java.util.*

• groovy.lang.*

• groovy.util.*

Special operators

• Elvis operator

• ?. operator

def name = person.name ?: "unknown"

def name = person?.name

Initializers• Java:

• Groovy:

int[] array = { 1, 2, 3}

int[] array = [1,2,3]

• { … } block reserved for closures

Initializers

def list = [1, 2, 3, 4 ,5] def map = [a: 1, b: 2, c:3] def regex = ~/.*foo.*/def range = 128..255def closure = {a, b -> a + b}

• other available initializers:

== operator

• == in groovy translates to: a.compareTo(b) == 0 if they are Comparable a.equals(b) otherwise

Groovy truth

• in Java:

• in Groovy:if(s)

if(s != null && s.length() > 0)

Package scope

• Java: package private field

• Groovy: property

• package private field in groovy:

class Person { String name}

class Person { @PackageScope String name}

Multi-methods

• java: result = 2 (method chosen at compile time)

• groovy: result = 1 (method chosen at run time)

int method(String arg) { return 1;}int method(Object arg) { return 2;}

Object o = "Object";int result = method(o);

Properties

public class Pokemon { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}

Pokemon pokemon = new Pokemon();pokemon.setName("Pikachu");

public class Pokemon { String name; }

Pokemon pokemon = new Pokemon(name: "Pikachu") pokemon.setName("Raichu")

Annotation processing

• no annotation processing in Groovy

• AST transformations

• example: @Immutable - implements immutable “by the book”

AST transformations example

public final class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public int hashCode() { return age + 31 * name.hashCode(); } @Override public boolean equals(Object other) { if(other == null) { return false; } if(this == other) { return true; } if(Person.class != other.getClass()) { return false; } Person otherPerson = (Person) other; if(!name.equals(otherPerson.name)) { return false; } if(age != otherPerson.age) { return false; } return true; } @Override public String toString() { return "Person(" + name + ", " + age + ")"; } }

import groovy.transform.Immutable@Immutablepublic class Person { String name; int age; }

with {} method

view = new TextView(context);view.setName(name);view.setTextSize(16f);view.setTextColor(Color.WHITE);

view = new TextView(context); view.with { text = name textSize = 16f textColor = Color.WHITE}

Resource handling

File f = new File("/sdcard/dir/f.txt");if(f.exists() && f.canRead()) { FileInputStream fis = null; try { fis = new FileInputStream(f); byte[] bytes = new byte[fis.available()]; while(fis.read(bytes) != -1) {}; textView.setText(new String(bytes)); } catch(IOException e) { //handle } finally { if(fis != null) { try { fis.close(); } catch(IOException e) { //ignore } } }} else { //handle}

def f = new File("/sdcard/dir/f.txt");if(f.exists() && f.canRead()) { f.withInputStream { fis -> def bytes = new byte[fis.available()] while(fis.read(bytes) != -1) {} textView.setText(new String(bytes)) }}

HTTP GET example

def url = "https://api.github.com/repos" + "groovy/groovy-core/commits"def commits = new JsonSlurper().parseText(url.toURL().text)assert commits[0].commit.author.name == "Cedric Champeau"

• easy to parse JSON REST API:

But there is more

• all the differences are described:http://groovy-lang.org/differences.html

Groovy project setup

Groovy project setup

Groovy project setup

Groovy project setup

Groovy project setup

Groovy project setup

Modify build.gradlebuildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.0.1' classpath 'me.champeau.gradle:gradle-groovy-android-plugin:0.3.0' } } apply plugin: 'com.android.application'apply plugin: 'me.champeau.gradle.groovy-android'android { …} dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile ‘org.codehaus.groovy:groovy-all:2.4.3' … }

Add groovy code

• rename class files from .java to .groovy

• Android Studio has autocomplete support!

Proguard

-dontobfuscate-keep class org.codehaus.groovy.reflection.** { *; } -keep class org.codehaus.groovy.vmplugin.** { *; } -keep class org.codehaus.groovy.runtime.dgm* { *; } -keepclassmembernames class org.codehaus.groovy.runtime.dgm* { *;} -keepclassmembernames class ** implements org.codehaus.groovy.runtime.GeneratedClosure { *;} -dontwarn org.codehaus.groovy.**-dontwarn groovy**

Groovy overhead

Java Groovy

Without Proguard 947 kB 2.9 MB

With Proguard 719 kB 1.6 MB

Android Groovy libraries

Libraries

• all Android libraries can be used with Groovy

• caveat: annotation processing won’t be run (except for .java files)

Swiss knife • Butterknife for Groovy

• same annotations as Butterknife

• in onCreate() add:

SwissKnife.inject(this);SwissKnife.restoreState(this, savedInstanceState);

compile ‘com.arasthel:swissknife:1.2.3'

• in build.gradle add:

The good

• less boilerplate and more concise code

• closures

• neat Exception stacktraces for closures (vs Java 8 lambdas)

The bad

• a little bit slower than Java Android project

• larger .apk

• no annotation processing (APT)

Conclusion

• good for smaller projects

• faster to code

• lots of syntax sugar

• add some overhead to performance and .apk size

Resources

• Groovy presentation by Guillaume Laforge: https://speakerdeck.com/glaforge/groovy-on-android-droidcon-paris-2014

• Groovy official site:http://groovy-lang.org/

• groovy project example:https://github.com/ikust/groovy-pokemons

top related