Improve your Android-Fu with Kotlin
-
Upload
nicolas-frankel -
Category
Software
-
view
1.001 -
download
0
Transcript of Improve your Android-Fu with Kotlin
POWER-UP YOUR ANDROID-FU WITH KOTLIN@NICOLAS_FRANKEL
@nicolas_frankel - Improve your Android-Fu with Kotlin 2
ME, MYSELF AND I
Blah, blah, blah…
@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
@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
@nicolas_frankel - Improve your Android-Fu with Kotlin 5
ORIGINAL STACK
Dagger 2ButterknifeRetro-lambdaStreamsGreen Robot’s EventBusPicasso
@nicolas_frankel - Improve your Android-Fu with Kotlin 6
OUTLINE
Kotlin - the languageLibraries• Stdlib• Kotlin extensions for Android•Anko
@nicolas_frankel - Improve your Android-Fu with Kotlin 7
KOTLIN
Language developed by JetBrainsOpen SourceCompiles to• JVM bytecode• JavaScript (experimental)
A "simpler Scala"
@nicolas_frankel - Improve your Android-Fu with Kotlin 8
KOTLINFunctional and object-orientedStatically typedNull safetyNo checked exceptionsNamed & optional argumentsLambdasExtension functionsJava compatibility(And more...)
@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!")}
@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" }}
@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' }}
@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; }}
@nicolas_frankel - Improve your Android-Fu with Kotlin 13
PAIN POINTS
Verbose!•Not specific to Android•Unfortunately Java
@nicolas_frankel - Improve your Android-Fu with Kotlin 14
KOTLIN SOLUTION
class AddTaskEvent(task: Task, val list: List) : AbstractTaskEvent(task)
@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); }}
@nicolas_frankel - Improve your Android-Fu with Kotlin 16
PAIN POINTS
Artificial groupingUtility class•No real Object, nor state
@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)}
@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);
@nicolas_frankel - Improve your Android-Fu with Kotlin 19
PAIN POINTS
Really, pass all those null values?Create local variable for ease of use
@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)}
@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)
@nicolas_frankel - Improve your Android-Fu with Kotlin 22
KOTLIN LIBRARY
Standard API for the language
@nicolas_frankel - Improve your Android-Fu with Kotlin 23
SETUP – APP/BUILD.GRADLE
dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"}
@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; }}
@nicolas_frankel - Improve your Android-Fu with Kotlin 25
PAIN POINTS
Utility classCannot return the object directly•Have to create a local variable
@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}
@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) }}
@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
@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" }}
@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(...); }}
@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(...); }}
@nicolas_frankel - Improve your Android-Fu with Kotlin 32
PAIN POINTS
Do I have to detail???
@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(...) }}
@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
@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); }}
@nicolas_frankel - Improve your Android-Fu with Kotlin 36
PAIN POINTS
CastSetter (?)
@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 }}
@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)}
@nicolas_frankel - Improve your Android-Fu with Kotlin 39
PAIN POINTS
Map-based APICast
@nicolas_frankel - Improve your Android-Fu with Kotlin 40
ANKO SOLUTION
a.inputMethodManager.toggleSoftInput( SHOW_FORCED, 0)a.inputMethodManager.toggleSoftInput( HIDE_IMPLICIT_ONLY, 0)
@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();
@nicolas_frankel - Improve your Android-Fu with Kotlin 42
PAIN POINTS
Verbose +++Not structured
@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()
@nicolas_frankel - Improve your Android-Fu with Kotlin 44
FINAL STACK
Dagger 2Butterknife Kotlin ext.Retro-lambda KotlinStreams KotlinGreen Robot’s EventBusPicasso
@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
@nicolas_frankel - Improve your Android-Fu with Kotlin 46
PITFALL
Null-able types
@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
@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
@nicolas_frankel - Improve your Android-Fu with Kotlin 49
MY EXPERIENCE
More expressiveHigher-level abstractionsOne single class I couldn’t migrate•Dagger 2 module
@nicolas_frankel - Improve your Android-Fu with Kotlin 50
Q&A
http://blog.frankel.ch/@nicolas_frankel http://frankel.in/