Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introducing Kotlin in an Android Project (BlrDroid Meetup, April 2018)

Ce1ca64f3265f01a8718a622427f0a1d?s=47 Jitin
April 21, 2018

Introducing Kotlin in an Android Project (BlrDroid Meetup, April 2018)

Kotlin is a great language addition to Android. In this presentation, we discuss details of how we introduced kotlin in a live project, tackled various challenges and finally put it in production.

Ce1ca64f3265f01a8718a622427f0a1d?s=128

Jitin

April 21, 2018
Tweet

More Decks by Jitin

Other Decks in Programming

Transcript

  1. Introducing Kotlin in Android Project # B L R K

    O T L I N
  2. Senior Android Developer Amadeus Software Labs Hello! I am Jitin

    Sharma @js_2892
  3. About the App Uses a lot of open libraries from

    Timber to Play Services Completely written in Java Already in production with multiple customers and million plus downloads
  4. Where we stood ~45000 255 lines of code java classes

  5. WHY KOTLIN

  6. Immutability Type/Null Safety Extensions Lambdas Interoperability

  7. SAFETY AND IMMUTABILITY Nullability makes you rethink your life choices.

    Immutability makes you appreciate final keyword in Java
  8. STANDARD LIBRARY supportActionBar?.apply { setDisplayHomeAsUpEnabled(true) setDisplayShowHomeEnabled(true) } if (getArguments() !=

    null) { } arguments?.let{ }
  9. SO MANY STANDARDS config?.decoderParams?.enabled = true config?.decoderParams?.redundancy = true config?.decoderParams?.length1

    = 2 config?.decoderParams?.length2 = 16 config?.decoderParams?.apply { enabled = true redundancy = true length1 = 2 length2 = 16 } config?.decoderParams?.run { enabled = true redundancy = true length1 = 2 length2 = 16 } config?.decoderParams?.let { it.enabled = true it.redundancy = true it.length1 = 2 it.length2 = 16 }
  10. STANDARD LIBRARY

  11. https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84 HOW TO STANDARD.KT

  12. SWITCH to WHEN Java Kotlin • Direct assignment to variable

    as an result of when closure if (fragment instanceof HomeFragment) { // Logic here } val view = when (viewType) { 1 -> layoutInflater.inflate(R.layout.item_pax_checkbox, parent, false) else -> layoutInflater.inflate(R.layout.item_pax_type, parent, false) } when(fragment) { is HomeFragment -> { } }
  13. BYE BYE BUTTERKNIFE • Usage in ViewHolders - still experimental

    • Using override method onViewCreated instead of onCreateView in Fragments Java Kotlin @BindView(R.id.bottomLayout) LinearLayout bottomLayout; import kotlinx.android.synthetic.main.activity_main.* bottomLayout.forEachChild { }
  14. EXTENSION FUNCTIONS fun View.show() { this.visibility = View.VISIBLE } fun

    Context.dpToPx(dp : Int): Float { val displayMetrics = this.resources.displayMetrics return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)).toFloat() } fun Drawable.withTint(colorInt: Int): Drawable { return with(this) { DrawableCompat.wrap(this).apply { DrawableCompat.setTint(this, colorInt) } } }
  15. EXTENSION FUNCTIONS Java Kotlin fun ImageView.loadImage(url: String) { Picasso.with(context) .load(url)

    .into(this) } Helper.loadImage(banner, "https://"); cityImageView.loadImage(destination.imageUrl)
  16. SUPER-POWERED DATA CLASSES @Parcelize data class City(var name: String? =

    null, var code: Int = 0) : Parcelable copy() equals() hashcode() newArray() writeToParcel() createFromParcel() describeContents()
  17. VISIBILITY private public protected internal • By default, everything is

    public • All classes are declared final by default. Use open to make classes extendible. • Subclasses should be defined as inner to access variables of outer class(useful in ViewHolders) File level Module Level Everywhere Subclass level
  18. S’MORE FEATURES typealias SessionData = ArrayList<MutableMap<String, UserSession>> tailrec fun HashMap<String,String>.colorFinder(key:

    String): String? { val value = this[key] as String return if (value.startsWith("#")) { value } else { this.colorFinder(value) } } val appVersion: String get() = BuildConfig.VERSION_NAME
  19. INTEROPERABILITY becomes a priority when inheriting a large java codebase

  20. HANDLING INTEROP • In most cases Kotlin automatically takes care

    of interoperability. • void is converted to Unit when calling in Kotlin. • Empty getters and setters are converted to Properties. • Annotations in Java are respected by Kotlin to specify nullability of a certain variable.
  21. FROM API 27, ANDROID ALSO HELPED @Nullable final public FragmentActivity

    getActivity() { return mHost == null ? null : (FragmentActivity) mHost.getActivity(); } Fragment.java(API 27) • context, activity and bundle with Nullable annotation are no longer platform types. • It’s always good to use Annotations on existing java code which could be used in Kotlin
  22. JVM ANNOTATIONS class RequestCreator { companion object { fun buildUri(baseUrl:

    String): Uri { return Uri.parse(baseUrl).buildUpon().build() } } } RequestCreator.Companion.buildUri(“https://"); RequestCreator.buildUri("https://") Java Kotlin RequestCreator.kt
  23. JVM ANNOTATIONS class RequestCreator { companion object { @JvmStatic fun

    buildUri(baseUrl: String): Uri { return Uri.parse(baseUrl).buildUpon().build() } } } RequestCreator.buildUri("https://"); RequestCreator.buildUri("https://") Java Kotlin RequestCreator.kt
  24. JVM ANNOTATIONS fun ImageView.loadImage(url: String) { Picasso.with(context) .load(url) .into(this) }

    HelperKt.loadImage(banner, "https://"); Java Helper.kt
  25. JVM ANNOTATIONS @file:JvmName("Helper") package ... import ... fun ImageView.loadImage(url: String)

    { Picasso.with(context) .load(url) .into(this) } Helper.loadImage(banner, "https://"); Java Helper.kt
  26. JVM ANNOTATIONS @JvmName("stringToIntSafely") fun String.toIntSafely() { try { this.toInt() }

    catch (_: Throwable) { } } Helper.stringToIntSafely(request.getId()); arguments?.getString("id")?.toIntSafely() Java Kotlin Helper.kt
  27. EXCEPTION HANDLING @Throws(Exception::class) fun exceptionalLogic() { } try { caller.exceptionalLogic();

    } catch (Exception e) { e.printStackTrace(); } caller.exceptionalLogic() Java Kotlin Helper.kt
  28. INTEROP WITH LAMBDAS class Caller { fun init(listener: (value: Int)

    -> Unit) { // Logic here } } caller.init { value: Int -> } Kotlin Caller.kt Java ??? No support for Lambda in Java 7
  29. class Caller { fun init(listener: SelectionListener) { } } caller.init(object

    : SelectionListener { override fun selected(value: Int) { } }) Kotlin Caller.kt Java caller.init(new SelectionListener() { @Override public void selected(int value) { } }); interface SelectionListener { fun selected(value: Int) } SelectionListener.kt No SAM conversion for Kotlin interface :(
  30. class Caller { fun init(listener: SelectionListener) { } } caller.init(SelectionListener

    { }) Kotlin Caller.kt Java caller.init(new SelectionListener() { @Override public void selected(int value) { } }); interface SelectionListener { void selected(int value); } SelectionListener.java Automatic SAM conversion for Java interface :)
  31. WHAT ABOUT JAVA 8 April 2016 Support for Java 8

    announced with Jack toolchain March 2017 Jack toolchain is deprecated April 2017 Java 8 support is merged into dx toolchain May 2017 Kotlin is announced as first class language for Android Nobody cares about Java 8 anymore
  32. TRY JAVA 8?

  33. INTEROP WITH JAVA 8 class Caller { fun init(listener: (value:

    Int) -> Unit) { // Logic here } } caller.init { value: Int -> } Kotlin Caller.kt Java caller.init(value -> { return Unit.INSTANCE; }); Return type necessary in Java lambdas
  34. THAT MEANS… list.filter { it.startsWith("0") }.map { it.toInt() } Kotlin

    Java List<String> filtered = filter(list, value -> value.startsWith("0")); List<Integer> mapped = map(list, Integer::parseInt); Statically import methods from Kotlin Collection framework • Kotlin Utility methods could be directly used in your Java code. More idiomatic usage in Kotlin, but still…
  35. THAT MEANS… Kotlin Java • Create your own Utils with

    higher order functions debugMode { StrictMode.enableDefaults() } debugMode(() -> { StrictMode.enableDefaults(); return Unit.INSTANCE; }); inline fun debugMode(block: () -> Unit) { if (BuildConfig.DEBUG) { block() } }
  36. LINT AND CODE STYLE • Relying mostly on Android Studio

    lint checks for Kotlin. • Android now has a dedicated style guide and interop guide for Kotlin. • https://android.github.io/kotlin-guides/style.html • https://android.github.io/kotlin-guides/interop.html • https://github.com/shyiko/ktlint
  37. AS 3.2 LINT UPDATES

  38. BUSINESS AS USUAL

  39. IMPACTS When things weren’t cool

  40. BUILD

  41. BUILD • CI server build time increased by 30-50%. •

    Kotlin’s compilation time is slower for clean builds. • However incremental compilation is faster than Java(enabled by default from 1.1.1). • Android Studio builds generally showed a difference of 10-20% as we moved from Gradle 2.14 -> 4.1, Kotlin 1.1.x -> 1.2.x
  42. JUnit testcases with Robolectric and Mockito Publish results to Sonarqube

    dashboard Jenkins for CI Code in bitbucket HIGHER LEVEL WORKFLOW
  43. TESTING AND QUALITY • Test cases were written in Kotlin.

    • Jacoco didn’t provide any coverage reports for Kotlin. • Sonarqube dashboard was affected due to unavailability of code coverage for Kotlin. When we started
  44. TESTING AND QUALITY • Jacoco problem resolved by resolving correct

    class directories. • Sonarqube code coverage works fine as it uses Jacoco binary. • Jacoco has teeny tiny issues with generated methods. • Kotlin is still not supported by Sonarqube officially(third party plugins are present, though) • Quality checks and line-by-line coverage not available on Sonarqube Where we are now
  45. Where we started ~45000 255 lines of code java classes

  46. Baby Steps ~45000 250 lines of code Java classes 30

    ~5000 Kotlin classes lines of code
  47. WHAT WE ACHIEVED • Significantly lower rates of crashes in

    Kotlin files. • Better Kotlin education among developers. • Newer projects migrated to Kotlin completely. • Backend team also want a piece of Kotlin(probably got fed up of our bad java puns). • Human interaction with iOS Developers (Swift <=> Kotlin).
  48. Thanks! twitter.com/@js_2892 Any questions?