Slide 1

Slide 1 text

Groovy on Android Guillaume Laforge Groovy project lead @glaforge

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

Total Android Newbie!

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Android is in the Java stone age state

Slide 6

Slide 6 text

Is there something we can do about it?

Slide 7

Slide 7 text

Yes, Groovy!

Slide 8

Slide 8 text

New York Times — Getting Groovy with Android 4

Slide 9

Slide 9 text

New York Times — Getting Groovy with Android 4 http://bit.ly/nyt-groovy

Slide 10

Slide 10 text

New York Times — Getting Groovy with Android 5

Slide 11

Slide 11 text

New York Times — Getting Groovy with Android 5 New York Times recruits a Groovy / Android expert http://bit.ly/nyt-job

Slide 12

Slide 12 text

What does NYT likes about Groovy on Android? • No Java 8, no lambda on Android… 6 Func0 func = new Func0() { @Override public String call() { return "my content"; } }; Async.start(func);

Slide 13

Slide 13 text

What does NYT likes about Groovy on Android? • No Java 8, no lambda on Android… 7 Async.start { "my content" }

Slide 14

Slide 14 text

What does NYT likes about Groovy on Android? • No Java 8, no lambda on Android… 7 Async.start { "my content" } Good bye annonymous inner classes!

Slide 15

Slide 15 text

What does NYT likes about Groovy on Android? • Groovy code more concise and more readable • but just as type-safe as needed!
 (with @TypeChecked) • but just as fast as needed!
 (with @CompileStatic) 8

Slide 16

Slide 16 text

@glaforge — Groovy on Android Brief overview of Groovy

Slide 17

Slide 17 text

@glaforge — Groovy on Android Brief overview of Groovy You probably know it through Gradle already!

Slide 18

Slide 18 text

Groovy — a multi-faceted language Open-source project (Apache 2 licensed) • http://groovy.codehaus.org/ • http://beta.groovy-lang.org/ 10

Slide 19

Slide 19 text

Groovy — a multi-faceted language Open-source project (Apache 2 licensed) • http://groovy.codehaus.org/ • http://beta.groovy-lang.org/ 10 New « shiny » website coming soon!

Slide 20

Slide 20 text

Groovy — a multi-faceted language Alternative language 
 for the JVM 11

Slide 21

Slide 21 text

Groovy — a multi-faceted language Alternative language 
 for the JVM 11 An alternative language for the JVM

Slide 22

Slide 22 text

Groovy — a multi-faceted language Alternative language 
 for the JVM 11 With 3 million downloads a year

Slide 23

Slide 23 text

Groovy — a multi-faceted language Closely 
 resembles 
 Java 12

Slide 24

Slide 24 text

Groovy — a multi-faceted language Closely 
 resembles 
 Java 12 Java code is also valid Groovy code!

Slide 25

Slide 25 text

Groovy — a multi-faceted language Closely 
 resembles 
 Java 12 But Groovy goes beyond!

Slide 26

Slide 26 text

Groovy — a multi-faceted language Multiple 
 programming 
 flavors 13

Slide 27

Slide 27 text

Groovy — a multi-faceted language Multiple 
 programming 
 flavors 13 Object-oriented

Slide 28

Slide 28 text

Groovy — a multi-faceted language Multiple 
 programming 
 flavors 13 Dynamic

Slide 29

Slide 29 text

Groovy — a multi-faceted language Multiple 
 programming 
 flavors 13 Functional

Slide 30

Slide 30 text

Groovy — a multi-faceted language Multiple 
 programming 
 flavors 13 Statically type checked and / or compiled

Slide 31

Slide 31 text

Groovy — a multi-faceted language Seamless Java integration
 & interoperability 14

Slide 32

Slide 32 text

Groovy — a multi-faceted language Seamless Java integration
 & interoperability 14 No bridge to cross between languages

Slide 33

Slide 33 text

@glaforge — Groovy on Android Let’s get started?

Slide 34

Slide 34 text

With a Hello World? 16

Slide 35

Slide 35 text

Android Studio 17

Slide 36

Slide 36 text

Android Studio 17 Click on « New Project »

Slide 37

Slide 37 text

Android Studio 18

Slide 38

Slide 38 text

Android Studio 18 Fill in the project details

Slide 39

Slide 39 text

Android Studio 19

Slide 40

Slide 40 text

Android Studio 19 Choose your target platform

Slide 41

Slide 41 text

Android Studio 20

Slide 42

Slide 42 text

Android Studio 20 Create a 
 blank activity

Slide 43

Slide 43 text

Android Studio 21

Slide 44

Slide 44 text

Android Studio 21 Details for your new activity

Slide 45

Slide 45 text

Android Studio 22

Slide 46

Slide 46 text

Android Studio 22 Now let’s have fun!

Slide 47

Slide 47 text

Modify your app’s Gradle build 23 apply plugin: 'com.android.application' android { compileSdkVersion 20 buildToolsVersion "20.0.0" defaultConfig { applicationId "com.appspot.glaforge.hellogroovyworld" minSdkVersion 15 targetSdkVersion 20 versionCode 1 versionName "1.0" } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 
 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) }

Slide 48

Slide 48 text

Modify your app’s Gradle build 23 apply plugin: 'com.android.application' android { compileSdkVersion 20 buildToolsVersion "20.0.0" defaultConfig { applicationId "com.appspot.glaforge.hellogroovyworld" minSdkVersion 15 targetSdkVersion 20 versionCode 1 versionName "1.0" } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 
 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:0.12.2' classpath 'me.champeau.gradle:gradle-groovy-android-plugin:0.3.0' } }

Slide 49

Slide 49 text

Modify your app’s Gradle build 23 apply plugin: 'com.android.application' android { compileSdkVersion 20 buildToolsVersion "20.0.0" defaultConfig { applicationId "com.appspot.glaforge.hellogroovyworld" minSdkVersion 15 targetSdkVersion 20 versionCode 1 versionName "1.0" } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 
 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } apply plugin: 'me.champeau.gradle.groovy-android' buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:0.12.2' classpath 'me.champeau.gradle:gradle-groovy-android-plugin:0.3.0' } }

Slide 50

Slide 50 text

Modify your app’s Gradle build 23 apply plugin: 'com.android.application' android { compileSdkVersion 20 buildToolsVersion "20.0.0" defaultConfig { applicationId "com.appspot.glaforge.hellogroovyworld" minSdkVersion 15 targetSdkVersion 20 versionCode 1 versionName "1.0" } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 
 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } compile 'org.codehaus.groovy:groovy:2.4.0-beta-3:grooid' apply plugin: 'me.champeau.gradle.groovy-android' buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:0.12.2' classpath 'me.champeau.gradle:gradle-groovy-android-plugin:0.3.0' } }

Slide 51

Slide 51 text

Java to Groovy… • Rename your activity from .java to .groovy • Remove… • public and return keywords • some parentheses • use the property notation • getMenuInflater() becomes menuInflater • use interpolated strings • and more. 24

Slide 52

Slide 52 text

Java to Groovy… 25 import android.app.Activity import android.os.Bundle import android.view.* class HelloGroovyWorld extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate savedInstanceState setContentView R.layout.activity_hello_groovy_world } boolean onCreateOptionsMenu(Menu menu) { menuInflater.inflate R.menu.hello_groovy_world, menu true } boolean onOptionsItemSelected(MenuItem item) { int id = item.itemId if (id == R.id.action_settings) { return true } super.onOptionsItemSelected item }

Slide 53

Slide 53 text

Run your Groovy-powered app in the emulator 26

Slide 54

Slide 54 text

What about weight? On a demo application (conference agenda) 27 Artifact Size Groovy JAR 4.5 MB Generated APK 2 MB After ProGuard 1 MB (8K methods)

Slide 55

Slide 55 text

ProGuard rules 28 -dontobfuscate -keep class org.codehaus.groovy.vmplugin.** -keep class org.codehaus.groovy.runtime.dgm* -keepclassmembers class org.codehaus.groovy.runtime.dgm* { *; } -keepclassmembers class ** implements org.codehaus.groovy.runtime.GeneratedClosure { *; } -dontwarn org.codehaus.groovy.** -dontwarn groovy**

Slide 56

Slide 56 text

@glaforge — Groovy on Android How does the Groovy support work?

Slide 57

Slide 57 text

Standard process 30 Compile-time Runtime

Slide 58

Slide 58 text

Standard process 30 Compile-time Runtime .class

Slide 59

Slide 59 text

Standard process 30 Compile-time Runtime .class .dex

Slide 60

Slide 60 text

Standard process 30 Compile-time Runtime .class .dex .apk

Slide 61

Slide 61 text

Standard process 30 Compile-time Runtime .class .dex .apk

Slide 62

Slide 62 text

First attempt — DiscoBot 31 Compile-time Runtime

Slide 63

Slide 63 text

First attempt — DiscoBot 31 Compile-time Runtime .apk

Slide 64

Slide 64 text

First attempt — DiscoBot 31 Compile-time Runtime .class .apk

Slide 65

Slide 65 text

First attempt — DiscoBot 31 Compile-time Runtime .class .jar .apk

Slide 66

Slide 66 text

First attempt — DiscoBot 31 Compile-time Runtime .class .jar .dex .apk

Slide 67

Slide 67 text

First attempt — DiscoBot 31 Compile-time Runtime .class .jar .dex .apk

Slide 68

Slide 68 text

First attempt — DiscoBot 31 Compile-time Runtime .class .jar .dex .apk « Ruboto » approach, slow & inneficient

Slide 69

Slide 69 text

New process — just like Java! 32 Compile-time Runtime

Slide 70

Slide 70 text

New process — just like Java! 32 Compile-time Runtime .class

Slide 71

Slide 71 text

New process — just like Java! 32 Compile-time Runtime .class .dex

Slide 72

Slide 72 text

New process — just like Java! 32 Compile-time Runtime .class .dex .apk

Slide 73

Slide 73 text

New process — just like Java! 32 Compile-time Runtime .class .dex .apk

Slide 74

Slide 74 text

Evaluating Groovy code at runtime 33 Compile-time Runtime .class .dex .apk

Slide 75

Slide 75 text

Evaluating Groovy code at runtime 33 Compile-time Runtime .class .dex .apk .class

Slide 76

Slide 76 text

Evaluating Groovy code at runtime 33 Compile-time Runtime .class .dex .apk .class .jar

Slide 77

Slide 77 text

Evaluating Groovy code at runtime 33 Compile-time Runtime .class .dex .apk .class .jar .dex

Slide 78

Slide 78 text

Evaluating Groovy code at runtime 33 Compile-time Runtime .class .dex .apk .class .jar .dex

Slide 79

Slide 79 text

@glaforge — Groovy on Android What does Groovy bring?

Slide 80

Slide 80 text

What does Groovy bring? 35 Optional

Slide 81

Slide 81 text

What does Groovy bring? 35 Optional Semi-colons

Slide 82

Slide 82 text

What does Groovy bring? 35 Optional Parentheses

Slide 83

Slide 83 text

What does Groovy bring? 35 Optional Typing

Slide 84

Slide 84 text

What does Groovy bring? 35 Optional return keyworkd

Slide 85

Slide 85 text

What does Groovy bring? 35 Optional public keyworkd

Slide 86

Slide 86 text

From Java to Groovy… 36 public class Greeter { private String owner; public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String greet(String name) { return "Hello " + name + ", I am " + owner; } } Greeter greeter = new Greeter(); greeter.setOwner("Guillaume"); System.out.println(greeter.greet("Marion"));

Slide 87

Slide 87 text

From Java to Groovy… 36 public class Greeter { private String owner; public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String greet(String name) { return "Hello " + name + ", I am " + owner; } } Greeter greeter = new Greeter(); greeter.setOwner("Guillaume"); System.out.println(greeter.greet("Marion")); class Greeter { String owner String greet(String name) { "Hello ${name}, I am ${owner}" } } def greeter = new Greeter(owner: "Guillaume") println greeter.greet("Marion")

Slide 88

Slide 88 text

Special Groovy syntax sugar — special operators 37

Slide 89

Slide 89 text

Special Groovy syntax sugar — special operators 37 // Groovy truth // if (s != null && s.length() > 0) {...} if (s) { ... } // Elvis def name = person.name ?: "unknown" // save navigation order?.lineItem?.item?.name

Slide 90

Slide 90 text

Special Groovy syntax sugar — special operators 37 // Groovy truth // if (s != null && s.length() > 0) {...} if (s) { ... } // Elvis def name = person.name ?: "unknown" // save navigation order?.lineItem?.item?.name if (person.name != null && person.name.length() > 0)

Slide 91

Slide 91 text

Special Groovy syntax sugar — special operators 37 // Groovy truth // if (s != null && s.length() > 0) {...} if (s) { ... } // Elvis def name = person.name ?: "unknown" // save navigation order?.lineItem?.item?.name Copied by Swift, C# 
 and CoffeeScript!

Slide 92

Slide 92 text

Special Groovy syntax sugar — special operators 37 // Groovy truth // if (s != null && s.length() > 0) {...} if (s) { ... } // Elvis def name = person.name ?: "unknown" // save navigation order?.lineItem?.item?.name Anything null in the chain? Null

Slide 93

Slide 93 text

Special Groovy syntax sugar — special operators 37 // Groovy truth // if (s != null && s.length() > 0) {...} if (s) { ... } // Elvis def name = person.name ?: "unknown" // save navigation order?.lineItem?.item?.name Better NPEs: Cannot get property name on null object

Slide 94

Slide 94 text

Special Groovy syntax sugar — collections, regex, closures 38 // lists def list = [1, 2, 3, 4, 5] // maps def map = [a: 1, b: 2, c: 3] // regular expressions def regex = ~/.*foo.*/ // ranges def range 128..255 // closures def adder = { a, b -> a + b }

Slide 95

Slide 95 text

Builders

Slide 96

Slide 96 text

Builders With closures come Groovy « builders »!

Slide 97

Slide 97 text

Groovy builders — XML, JSON… Android views & layouts! 40 import groovy.json.* def json = new JsonBuilder() json.person { name 'Guillaume' age 37 daughters 'Marion', 'Erine' address { street '1 Main St' zip 75001 city 'Paris' } }

Slide 98

Slide 98 text

Groovy builders — XML, JSON… Android views & layouts! 40 import groovy.json.* def json = new JsonBuilder() json.person { name 'Guillaume' age 37 daughters 'Marion', 'Erine' address { street '1 Main St' zip 75001 city 'Paris' } } { "person": { "name": "Guillaume", "age": 37, "daughters": [ "Marion", "Erine" ], "address": { "street": "1 Main St", "zip": 75001, "city": "Paris" } } }

Slide 99

Slide 99 text

HTTP GET and JSON parsing in 4 lines 41 import groovy.json.* 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'

Slide 100

Slide 100 text

HTTP GET and JSON parsing in 4 lines 41 import groovy.json.* 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' An HTTP GET in a one-liner!

Slide 101

Slide 101 text

HTTP GET and JSON parsing in 4 lines 41 import groovy.json.* 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' No complex object graph marshalling!

Slide 102

Slide 102 text

Annotations

Slide 103

Slide 103 text

Annotations Actually, code transformations triggered by annotations

Slide 104

Slide 104 text

Annotations Actually, code transformations triggered by annotations No APT, sorry!

Slide 105

Slide 105 text

AST transformations — only a short list! Code generation • @ToString • @EqualsAndHashCode • @Canonical • @TupleConstructor • @InheritConstructors • @Category • @Lazy • @Sortable • @Builder Class design • @Delegate • @Immutable • @Memoized • @Singleton Compiler directives • @AnnotationCollector • @DelegatesTo • @TypeChecked • @CompileStatic • @TailRecursive 43

Slide 106

Slide 106 text

AST transformations — @Immutable Implement immutability by the book • final class • tuple-style constructor • private final backing fields • defensive copying of collections • equals() and hashCode() methods • toString() method • ... 44

Slide 107

Slide 107 text

AST transformations — @Immutable • A person class • a String name • an int age 45 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; } public int hashCode() { return age + 31 * name.hashCode(); } 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.getName()) { return false; } if (age != otherPerson.getAge()) { return false; } return true; } public String toString() { return "Person(" + name + ", " + age + ")"; } }

Slide 108

Slide 108 text

AST transformations — @Immutable • A person class • a String name • an int age 46 import groovy.transform.* @Immutable class Person { String name int age }

Slide 109

Slide 109 text

AST transformations 47

Slide 110

Slide 110 text

AST transformations 47 Groovy allows you to be lazy

Slide 111

Slide 111 text

AST transformations 47 The compiler will do the job for you

Slide 112

Slide 112 text

AST transformations 47 More concise, more readable code

Slide 113

Slide 113 text

AST transformations 47 Less stuff to maintain and worry about

Slide 114

Slide 114 text

Traits • Like interfaces, but with method bodies – similar to Java 8 interface default methods • Elegant way to compose behavior – multiple inheritance without the « diamond » problem • Traits can also be stateful – traits can have properties like normal classes • Compatible with static typing and static compilation – class methods from traits also visible from Java classes • Also possible to implement traits at runtime 48

Slide 115

Slide 115 text

Traits — example: melix / speakertime 49 @CompileStatic class PresentationActivity extends Activity implements GoogleApiProvider { // ... protected void onCreate(Bundle savedState) { super.onCreate(savedState) // ... createGoogleApi() } protected void onStart() { super.onStart() connectGoogleApi() } protected void onStop() { super.onStop() disconnectGoogleApi() } // ... @CompileStatic trait GoogleApiProvider { GoogleApiClient googleApiClient void createGoogleApi() { /* ... */ } void connectGoogleApi() { /* ... */ } void disconnectGoogleApi() { /* ... */ } }

Slide 116

Slide 116 text

Compare Java and Groovy 50

Slide 117

Slide 117 text

Compare Java and Groovy 50

Slide 118

Slide 118 text

Event listeners 51 button.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { Log.i(tag, "clicked!") } })

Slide 119

Slide 119 text

Event listeners 51 button.onClickListener = { Log.i(tag, "clicked!") } button.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { Log.i(tag, "clicked!") } })

Slide 120

Slide 120 text

Properties and equality 52 if (intent.getAction().equals(Intent.ACTION_VIEW)) { Log.i(tag, "view"); }

Slide 121

Slide 121 text

Properties and equality 52 if (intent.getAction().equals(Intent.ACTION_VIEW)) { Log.i(tag, "view"); } if (intent.action == Intent.ACTION_VIEW) { Log.i(tag, "view") }

Slide 122

Slide 122 text

Groovy Development Kit methods 53 new Thread() { public void run() { // … } }.start();

Slide 123

Slide 123 text

Groovy Development Kit methods 53 new Thread() { public void run() { // … } }.start(); Thread.start { // … }

Slide 124

Slide 124 text

Groovy’s with {} method 54 view = new TextView(context); view.setText(name); view.setTextSize(16f); view.setTextColor(Color.WHITE);

Slide 125

Slide 125 text

Groovy’s with {} method 54 view = new TextView(context); view.setText(name); view.setTextSize(16f); view.setTextColor(Color.WHITE); view = new TextView(context) view.with { text = name textSize = 16f textColor = Color.WHITE }

Slide 126

Slide 126 text

Groovy Truth and GStrings 55 EditText phone = (EditText)findViewById(R.id.phone); if ((phone.getText() != null) && !phone.getText().equals("")) { String phoneString = parsePhone(phone.getText().toString()); Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneString)); startActivity(intent); }

Slide 127

Slide 127 text

Groovy Truth and GStrings 55 EditText phone = (EditText)findViewById(R.id.phone); if ((phone.getText() != null) && !phone.getText().equals("")) { String phoneString = parsePhone(phone.getText().toString()); Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneString)); startActivity(intent); } EditText phone = findViewById(R.id.phone) if (phone.text) { def phoneString = parsePhone(phone.text) def intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:${phoneString}")) startActivity intent }

Slide 128

Slide 128 text

Resource handling with closures and file methods 56 File f = new File("/sdcard/dir/f.txt"); if (f.exists() && f.canRead()) { FileInputStream fis = null; try { fis = new FileInputStream(rFile); byte[] bytes = new byte[fis.available()]; while (fis.read(bytes) != -1) {} textView.setText(new String(bytes)); } catch (IOException e) { // log and or handle } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // swallow } } } }

Slide 129

Slide 129 text

Resource handling with closures and file methods 56 File f = new File("/sdcard/dir/f.txt"); if (f.exists() && f.canRead()) { FileInputStream fis = null; try { fis = new FileInputStream(rFile); byte[] bytes = new byte[fis.available()]; while (fis.read(bytes) != -1) {} textView.setText(new String(bytes)); } catch (IOException e) { // log and or handle } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // swallow } } } } 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.text = new String(bytes) } }

Slide 130

Slide 130 text

Resource handling with closures and file methods 56 File f = new File("/sdcard/dir/f.txt"); if (f.exists() && f.canRead()) { FileInputStream fis = null; try { fis = new FileInputStream(rFile); byte[] bytes = new byte[fis.available()]; while (fis.read(bytes) != -1) {} textView.setText(new String(bytes)); } catch (IOException e) { // log and or handle } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { // swallow } } } } 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.text = new String(bytes) } } def f = new File("/sdcard/dir/f.txt") if (f.exists() && f.canRead()) { textView.text = f.text }

Slide 131

Slide 131 text

@glaforge — Groovy on Android What else?

Slide 132

Slide 132 text

What else? • Projects with dedicated Groovy support • Swiss Knife • similar to Butter Knife & 
 Android Annotations • Grooid Playground • a builder for creating views
 in a hierarchical & visual manner 58

Slide 133

Slide 133 text

Swiss Knife — Arasthel / SwissKnife 59

Slide 134

Slide 134 text

Swiss Knife — Arasthel / SwissKnife 59 Like Butter Knife & Android Annotations, but for Groovy

Slide 135

Slide 135 text

Swiss Knife 60 class MyActivity extends Activity { @OnClick(R.id.button) void onButtonClicked(Button button) { Toast.makeText(this, "Clicked", Toast.LENGTH_SHOT).show() } @OnBackground void doSomeProcessing(URL url) { // Contents will be executed on background } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate savedInstanceState setContentView R.layout.activity_main SwissKnife.inject this } }

Slide 136

Slide 136 text

Swiss Knife 60 class MyActivity extends Activity { @OnClick(R.id.button) void onButtonClicked(Button button) { Toast.makeText(this, "Clicked", Toast.LENGTH_SHOT).show() } @OnBackground void doSomeProcessing(URL url) { // Contents will be executed on background } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate savedInstanceState setContentView R.layout.activity_main SwissKnife.inject this } } View injection

Slide 137

Slide 137 text

Swiss Knife 60 class MyActivity extends Activity { @OnClick(R.id.button) void onButtonClicked(Button button) { Toast.makeText(this, "Clicked", Toast.LENGTH_SHOT).show() } @OnBackground void doSomeProcessing(URL url) { // Contents will be executed on background } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate savedInstanceState setContentView R.layout.activity_main SwissKnife.inject this } } Execute code outside the UI thread

Slide 138

Slide 138 text

Swiss Knife 60 class MyActivity extends Activity { @OnClick(R.id.button) void onButtonClicked(Button button) { Toast.makeText(this, "Clicked", Toast.LENGTH_SHOT).show() } @OnBackground void doSomeProcessing(URL url) { // Contents will be executed on background } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate savedInstanceState setContentView R.layout.activity_main SwissKnife.inject this } } Injection point of views and callbacks

Slide 139

Slide 139 text

Swiss Knife — available annotations • @OnUIThread • @OnBackground • @OnClick • @OnLongClick • @OnItemClick • @OnItemLongClick • @OnItemSelected • @OnChecked • @OnFocusChanged • @OnTouch • @OnPageChanged • @OnTextChanged • @OnEditorAction 61

Slide 140

Slide 140 text

Swiss Knife — available annotations • @OnUIThread • @OnBackground • @OnClick • @OnLongClick • @OnItemClick • @OnItemLongClick • @OnItemSelected • @OnChecked • @OnFocusChanged • @OnTouch • @OnPageChanged • @OnTextChanged • @OnEditorAction 61 AST transformations

Slide 141

Slide 141 text

Swiss Knife — setup 62 dependencies { … compile 'com.arasthel:swissknife:1.0.4' … }

Slide 142

Slide 142 text

Grooid Playground — karfunkel / grooid-playground • When you need to build dynamic views (ie. not XML-driven) 63 def layout = new RelativeLayout(this) layout.width = MATCH_PARENT layout.height = MATCH_PARENT layout.setPaddingRelative(64, 16, 64, 16) def textView = new TextView(this) textView.width = MATCH_PARENT textView.height = 20 textView.setText R.string.hello_world layout.addView textView setContentView(layout)

Slide 143

Slide 143 text

Grooid Playground — karfunkel / grooid-playground • When you need to build dynamic views (ie. not XML-driven) 63 def layout = new RelativeLayout(this) layout.width = MATCH_PARENT layout.height = MATCH_PARENT layout.setPaddingRelative(64, 16, 64, 16) def textView = new TextView(this) textView.width = MATCH_PARENT textView.height = 20 textView.setText R.string.hello_world layout.addView textView setContentView(layout) Imperative

Slide 144

Slide 144 text

Grooid Playground — karfunkel / grooid-playground • When you need to build dynamic views (ie. not XML-driven) 63 setContentView new AndroidBuilder().build(this) { relativeLayout(width: MATCH_PARENT, height: MATCH_PARENT, padding: [64.dip, 16.dip]) { textView(width: MATCH_PARENT, height: 20.dip, text: R.string.hello_world) } } Declarative, hierarchical, visual

Slide 145

Slide 145 text

@glaforge — Groovy on Android Want more?

Slide 146

Slide 146 text

Programming your Android applications in Groovy • You can use Groovy to code Android apps! • use Groovy 2.4.0-beta-1+ (latest: beta-4) • prefer @CompileStatic • Two great posts to get started: • http://bit.ly/grooid-1 • http://bit.ly/grooid-2 • Gradle plugin support: • http://bit.ly/grooid-gradle 65

Slide 147

Slide 147 text

Demo conference application 66

Slide 148

Slide 148 text

Demo conference application 66 Source code available: http://bit.ly/grooid-app

Slide 149

Slide 149 text

Demo Google Wear + Phone application 67

Slide 150

Slide 150 text

Demo Google Wear + Phone application 67 Source code available: http://bit.ly/grooid-wear

Slide 151

Slide 151 text

@glaforge — Groovy on Android Summary

Slide 152

Slide 152 text

Summary • Groovy can make your Android code… • more concise & readable • more maintainable • Without compromising • type safety • speed 69

Slide 153

Slide 153 text

Feedback welcome 70

Slide 154

Slide 154 text

Feedback welcome 70 We need you to help figure out how Groovy can help you!

Slide 155

Slide 155 text

@glaforge — Groovy on Android Q & A

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

Image credits • Stone age • http://3.bp.blogspot.com/-lMDyyBdibG4/UxDYLq5ItiI/AAAAAAAALf8/HPpKRixHOIE/s1600/Neanderthal+Man+1.jpg • Many thanks • http://www.trys.ie/wp-content/uploads/2013/06/many-thanks.jpg • Disclaimer • http://3.bp.blogspot.com/-RGnBpjXTCQA/Tj2h_JsLigI/AAAAAAAABbg/AB5ZZYzuE5w/s1600/disclaimer.jpg • Builders • http://detroittraining.com/wp-content/uploads/Construction-Women2.jpg • Newbie • http://contently.com/strategist/wp-content/uploads/2014/05/bigstock-Shocked-Computer-Nerd-1520709.jpg • Alternative rock band • http://upload.wikimedia.org/wikipedia/commons/b/b2/Arcade_Fire_live_20050315.ext.jpg • Twins • http://images.doctissimo.fr/1/jumeaux-jumelles/photo/hd/4424027442/137540656da/jumeaux-jumelles-jumeaux-jumelles-2-big.jpg • Annotations • http://3.bp.blogspot.com/-f94n9BHko_s/T35ELs7nYvI/AAAAAAAAAKg/qe06LRPH9U4/s1600/IMG_1721.JPG • Apple & Orange • http://cdni.wired.co.uk/1920x1280/a_c/comparison.jpg • We need you • http://media.moddb.com/images/mods/1/14/13849/WickedSunshine_UncleSam_Blank_800x1000.png 73

Slide 158

Slide 158 text

Image credits • Macarons • http://www.thatfoodcray.com/wp-content/uploads/2013/12/that-food-cray-pierre-herme-paris-hong-kong-christmas-flavors-foie-gras- truffle-9.jpg?4dd047 • Bridge • http://tenspeedhero.com/wp-content/uploads/Bridge_3.jpg • Swiss knife • http://www.formengifts.com/wp-content/uploads/2011/04/swiss-army-champ-multitool-knife2.jpg • Hello World • http://www.warrenpriestley.com/wp-content/uploads/2012/01/helloworld.gif • George Clooney • http://www.brewville.ca/wp-content/uploads/2014/05/nespresso-george-clooney.jpg • Weight scale • http://images.wisegeek.com/person-stands-on-scale.jpg • Nexus 5 • http://fs01.androidpit.info/userfiles/2692059/image/Blog/nexus-5-weiss_628.jpg • File icon • https://dl.vecnet.org/assets/default.png • Gear • http://www.pvzgears.com/wp-content/uploads/2013/03/gears2a.png • Sugar • http://images.wisegeek.com/cane-sugar.jpg • London • http://www.100percentoptical.com/images/2014/10/london.jpg 74