geecon - improve your android-fu with kotlin

Post on 17-Jan-2017

639 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Power-up your Android-Fu with Kotlin

@nicolas_frankel

Nicolas Fränkel, 12 May 2016

Me, Myself and IBlah, blah, blah…

@nicolas_frankel #kotlin #android

My experience in AndroidBack-end Java developer

Developing a To Do list application with some improvements

Images

Alarm

Multiple lists@nicolas_frankel #kotlin #android

My personal viewDeveloping Android app is a pain

Backend Java is very mature compared to Android

High-level libraries required to cope up with low-level APIs

@nicolas_frankel #kotlin #android

Starting stackDagger 2

Butterknife

Retro-lambda

Streams

Green Robot’s EventBus

Picasso@nicolas_frankel #kotlin #android

OutlineKotlin - the language

Libraries

Stdlib

Kotlin extensions for Android

Anko

@nicolas_frankel #kotlin #android

KotlinLanguage developed by JetBrains

Open Source

Compiles to

JVM bytecode

JavaScript (experimental)

A "simpler Scala"@nicolas_frankel #kotlin #android

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

@nicolas_frankel #kotlin #android

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!")}

@nicolas_frankel #kotlin #android

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

@nicolas_frankel #kotlin #android

Setup – app/build.gradleapply plugin: 'kotlin-android'

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

@nicolas_frankel #kotlin #android

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; }} @nicolas_frankel #kotlin #android

Pain pointsVerbose!

Not specific to Android

Unfortunately Java

@nicolas_frankel #kotlin #android

Kotlin solutionclass AddTaskEvent(task: Task, val list: List)

: AbstractTaskEvent(task)

@nicolas_frankel #kotlin #android

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); }}

@nicolas_frankel #kotlin #android

Pain pointsArtificial grouping

Utility class

No state so not a real Object

@nicolas_frankel #kotlin #android

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)}

Sample code• SQLiteDatabase db = getReadableDatabase();

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

@nicolas_frankel #kotlin #android

Pain pointsReally, pass all those null values?

Create local variable for ease of use

@nicolas_frankel #kotlin #android

Kotlin solution – part 1fun 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)}

@nicolas_frankel #kotlin #android

Kotlin solution – part 2readableDatabase.query(TASK_TABLE,

arrayOf(T_ID_COL, T_NAME_COL), orderBy = T_PRIO_COL)

@nicolas_frankel #kotlin #android

One-use private method

@nicolas_frankel #kotlin #android

Kotlin solutionNested methods

@nicolas_frankel #kotlin #android

Kotlin LibraryStandard API for the language

@nicolas_frankel #kotlin #android

Setup – app/build.gradledependencies {

compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

}

@nicolas_frankel #kotlin #android

Sample codepublic class DisplayMetricsGetter {

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

@nicolas_frankel #kotlin #android

Pain pointsUtility class

Cannot return the object directly

Have to create a local variable

@nicolas_frankel #kotlin #android

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

@nicolas_frankel #kotlin #android

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

@nicolas_frankel #kotlin #android

Kotlin extensions for Android

Plugin for the Kotlin compiler

Provide a "synthetic property" for each widget in a layout

@nicolas_frankel #kotlin #android

Setup – app/build.gradlebuildscript { repositories { jcenter() } dependencies { classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" }}

@nicolas_frankel #kotlin #android

Sample Codepublic class AActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstState) { super.onCreate(savedInstaState); setContentView(R.layout.task_add_item); View imageView = findViewById(R.id.new_task_img); imageView.setOnClickListener(...); }}

@nicolas_frankel #kotlin #android

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(...); }} @nicolas_frankel #kotlin #android

Pain pointsDo I have to detail???

@nicolas_frankel #kotlin #android

Kotlinx solutionimport kotlinx.android.synthetic.task_add_item.new_task_img

class AddTaskActivity : AppCompatActivity() {

override fun onCreate(savedInstState: Bundle?) { super.onCreate(savedInstState) setContentView(R.layout.task_add_item) new_task_img.setOnClickListener(...) }} @nicolas_frankel #kotlin #android

AnkoKotlin library for Android

Meant to replace XML with fluent DSL for GUI

But a lot of other niceties

@nicolas_frankel #kotlin #android

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_flip); flip.setDisplayedChild(1); }}

@nicolas_frankel #kotlin #android

Pain pointsCast

Setter (?)

@nicolas_frankel #kotlin #android

Anko solutionimport 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_flip) flip.displayedChild = 1 }} @nicolas_frankel #kotlin #android

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)}

Pain pointsMap-based API

Cast

@nicolas_frankel #kotlin #android

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

@nicolas_frankel #kotlin #android

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();

@nicolas_frankel #kotlin #android

Pain pointsVerbose +++

Not structured

@nicolas_frankel #kotlin #android

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()

@nicolas_frankel #kotlin #android

Final stackDagger 2

Butterknife Kotlin ext.

Retro-lambda Kotlin

Streams Kotlin

Green Robot’s EventBus

Picasso@nicolas_frankel #kotlin #android

Migration tacticsStart with standard classesThen with Android-dependent classes

Use Android Studio provided migration toolTake a classMigrate to Kotlin extensionMigrate to AnkoAfter each single change, test!

Repeat

@nicolas_frankel #kotlin #android

PitfallNull-able types

@nicolas_frankel #kotlin #android

Null-able vs. non null-able typesDifferent type whether value can be

null or not

T: cannot be null

T?: can be null

@nicolas_frankel #kotlin #android

Null-able vs. non null-able typesParameter types should use the right

kind

Know your API

Or read the docs

Or be conservative

@nicolas_frankel #kotlin #android

My experienceMore expressive

Higher-level abstractions

One single class I couldn’t migrate

Dagger 2 module

@nicolas_frankel #kotlin #android

Q&Ahttp://blog.frankel.ch/

@nicolas_frankel

http://frankel.in/

@nicolas_frankel #kotlin #android

top related