50
POWER-UP YOUR ANDROID-FU WITH KOTLIN @NICOLAS_FRANKEL

Improve your Android-Fu with Kotlin

Embed Size (px)

Citation preview

Page 1: Improve your Android-Fu with Kotlin

POWER-UP YOUR ANDROID-FU WITH KOTLIN@NICOLAS_FRANKEL

Page 2: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 2

ME, MYSELF AND I

Blah, blah, blah…

Page 3: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 3

MY EXPERIENCE IN ANDROID

Back-end Java developerDeveloping a To Do list application with some improvements• Images•Alarm•Multiple lists

Page 4: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 4

MY PERSONAL CONCLUSION

Developing Android app is a painBackend Java is very mature compared to AndroidHigh-level libraries required to cope up with low-level APIs

Page 5: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 5

ORIGINAL STACK

Dagger 2ButterknifeRetro-lambdaStreamsGreen Robot’s EventBusPicasso

Page 6: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 6

OUTLINE

Kotlin - the languageLibraries• Stdlib• Kotlin extensions for Android•Anko

Page 7: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 7

KOTLIN

Language developed by JetBrainsOpen SourceCompiles to• JVM bytecode• JavaScript (experimental)

A "simpler Scala"

Page 8: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 8

KOTLINFunctional and object-orientedStatically typedNull safetyNo checked exceptionsNamed & optional argumentsLambdasExtension functionsJava compatibility(And more...)

Page 9: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 9

HELLO WORLD!

package hello // optional semicolons

// namespace-level functions// types on the right// no special syntax for arrays// optional return typefun main(args: Array<String>) { println("Hello, world!")}

Page 10: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 10

SETUP - BUILD.GRADLE

buildscript { ext.kotlin_version = '1.0.0-beta-1038' repositories { jcenter() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" }}

Page 11: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 11

SETUP – APP/BUILD.GRADLE

apply plugin: 'kotlin-android'

android { sourceSets { main.java.srcDirs += 'src/main/kotlin' test.java.srcDirs += 'src/test/kotlin' }}

Page 12: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 12

SAMPLE CODEpublic class AddTaskEvent extends AbstractTaskEvent {

private final List list;

public AddTaskEvent(Task task, List list) { super(task); this.list = list; }

public List getList() { return list; }}

Page 13: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 13

PAIN POINTS

Verbose!•Not specific to Android•Unfortunately Java

Page 14: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 14

KOTLIN SOLUTION

class AddTaskEvent(task: Task, val list: List) : AbstractTaskEvent(task)

Page 15: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 15

SAMPLE CODEpublic class KeyboardDisplay {

public void show(Activity a) { InputMethodManager imm = (InputMethodManager) a.getSystemService(INPUT_METHOD_SERVICE); imm.toggleSoftInput(SHOW_FORCED, 0); }

public void hide(Activity a) { InputMethodManager imm = (InputMethodManager) a.getSystemService(INPUT_METHOD_SERVICE); imm.toggleSoftInput(HIDE_IMPLICIT_ONLY, 0); }}

Page 16: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 16

PAIN POINTS

Artificial groupingUtility class•No real Object, nor state

Page 17: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 17

KOTLIN SOLUTIONfun show(a: Activity) { val imm = a.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(SHOW_FORCED, 0)}

fun hide(a: Activity) { val imm = a.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(HIDE_IMPLICIT_ONLY, 0)}

Page 18: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 18

SAMPLE CODE

SQLiteDatabase db = getReadableDatabase();db.query(TASK_TABLE, new String[] { T_ID_COL, T_NAME_COL }, null, null, null, null, T_PRIO_COL);

Page 19: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 19

PAIN POINTS

Really, pass all those null values?Create local variable for ease of use

Page 20: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 20

KOTLIN SOLUTION – PART 1

fun SQLiteDatabase.query(table:String, columns:Array<String>, selection:String? = null, selectionArgs:Array<String>? = null, groupBy:String? = null, having:String? = null, orderBy:String? = null): Cursor { return query(table, columns, selection, selectionArgs, groupBy, having, orderBy)}

Page 21: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 21

KOTLIN SOLUTION – PART 2

readableDatabase.query(TASK_TABLE, arrayOf(T_ID_COL, T_NAME_COL), orderBy = T_PRIO_COL)

Page 22: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 22

KOTLIN LIBRARY

Standard API for the language

Page 23: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 23

SETUP – APP/BUILD.GRADLE

dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"}

Page 24: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 24

SAMPLE CODE

public class DisplayMetricsGetter {

public DisplayMetrics getFrom(Context c) { WindowManager wm = (WindowManager) c.getSystemService(WINDOW_SERVICE); DisplayMetrics metrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(metrics); return metrics; }}

Page 25: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 25

PAIN POINTS

Utility classCannot return the object directly•Have to create a local variable

Page 26: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 26

KOTLIN SOLUTION

fun getFrom(c: Context): DisplayMetrics { val wm = c.getSystemService(Context.WINDOW_SERVICE) as WindowManager val metrics = DisplayMetrics() wm.defaultDisplay.getMetrics(metrics) return metrics}

Page 27: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 27

KOTLIN SOLUTION

fun getFrom(c: Context): DisplayMetrics { val wm = c.getSystemService(Context.WINDOW_SERVICE) as WindowManager return DisplayMetrics().apply { wm.defaultDisplay.getMetrics(this) }}

Page 28: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 28

KOTLIN EXTENSIONS FOR ANDROID

Plugin for the Kotlin compilerProvide a "synthetic property" for each widget in a layout

Page 29: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 29

SETUP – APP/BUILD.GRADLE

buildscript { repositories { jcenter() } dependencies { classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" }}

Page 30: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 30

SAMPLE CODE

public class AddActivity extends AppCompatActivity {

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.task_add_item); View imageView = findViewById(R.id.new_task_img); imageView.setOnClickListener(...); }}

Page 31: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 31

SAMPLE CODE – WITH BUTTERKNIFEpublic class AddActivity extends AppCompatActivity {

@Bind(R.id.new_task_img) View imageView;

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.task_add_item); ButterKnife.bind(this); imageView.setOnClickListener(...); }}

Page 32: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 32

PAIN POINTS

Do I have to detail???

Page 33: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 33

KOTLINX SOLUTIONimport kotlinx.android.synthetic.task_add_item.new_task_img

class AddTaskActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.task_add_item) new_task_img.setOnClickListener(...) }}

Page 34: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 34

ANKO

Kotlin library for AndroidMostly about replacing XML with fluent DSL for GUIBut a lot of other niceties

Page 35: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 35

CODE SAMPLEpublic class AddAlarmClickListener implements View.OnClickListener {

@Override public void onClick(View view) { View rootView = view.getRootView(); ViewFlipper flip = (ViewFlipper) rootView.findViewById(R.id.new_task_alarm_flip); flip.setDisplayedChild(1); }}

Page 36: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 36

PAIN POINTS

CastSetter (?)

Page 37: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 37

ANKO SOLUTION

import org.jetbrains.anko.*class AddAlarmClickListener: View.OnClickListener {

override fun onClick(view: View) { val parent:View = view.rootView val flip = parent.find<ViewFlipper>(R.id.new_task_alarm_flip) flip.displayedChild = 1 }}

Page 38: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 38

CODE SAMPLEfun show(a: Activity) { val imm = a.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(SHOW_FORCED, 0)}

fun hide(a: Activity) { val imm = a.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager imm.toggleSoftInput(HIDE_IMPLICIT_ONLY, 0)}

Page 39: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 39

PAIN POINTS

Map-based APICast

Page 40: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 40

ANKO SOLUTION

a.inputMethodManager.toggleSoftInput( SHOW_FORCED, 0)a.inputMethodManager.toggleSoftInput( HIDE_IMPLICIT_ONLY, 0)

Page 41: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 41

CODE SAMPLEAlertDialog.Builder builder = new AlertDialog.Builder(activity);builder.setMessage("New list name");EditText editText = new EditText(activity);editText.setId( android.support.v7.appcompat.R.id.select_dialog_listview);String listName = global.getList().getName();editText.setText(listName, NORMAL);editText.selectAll();builder.setView(editText);builder.setPositiveButton("OK", editListNameListener);builder.setNegativeButton("Cancel", (dialog, which) -> { dialog.cancel();});AlertDialog dialog = builder.create();dialog.show();

Page 42: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 42

PAIN POINTS

Verbose +++Not structured

Page 43: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 43

ANKO SOLUTIONview.context.alert('New list name') { builder.setPositiveButton('OK', editListNameListener) negativeButton('Cancel') { cancel() } customView { editText(global.list.name) { id = an.sup.v7.appcompat.R.id.select_dialog_listview }.selectAll() }}.show()

Page 44: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 44

FINAL STACK

Dagger 2Butterknife Kotlin ext.Retro-lambda KotlinStreams KotlinGreen Robot’s EventBusPicasso

Page 45: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 45

MIGRATION TACTICSStart with standard classes• Then with Android-dependent classes

Use Android Studio provided migration toolTake a class•Migrate to Kotlin extension•Migrate to Anko• After each single change, test!

Repeat

Page 46: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 46

PITFALL

Null-able types

Page 47: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 47

NULL-ABLE VS. NON NULL-ABLE TYPES

Different type whether value can be null or not• T: cannot be null• T?: can be null

Page 48: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 48

NULL-ABLE VS. NON NULL-ABLE TYPES

Parameter types should use the right kind• Know your API•Or read the docs•Or be conservative

Page 49: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 49

MY EXPERIENCE

More expressiveHigher-level abstractionsOne single class I couldn’t migrate•Dagger 2 module

Page 50: Improve your Android-Fu with Kotlin

@nicolas_frankel - Improve your Android-Fu with Kotlin 50

Q&A

http://blog.frankel.ch/@nicolas_frankel http://frankel.in/