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

Exploring Kotlin on Android

Exploring Kotlin on Android

at Expedia

Deepanshu

May 03, 2016
Tweet

Other Decks in Programming

Transcript

  1. What is Kotlin? • Statically typed programming language   •

    JVM-based language developed by JetBrains • From industry not academia • 100% inter-operable with the Java language Open Source - https://github.com/JetBrains/kotlin
  2. Why Kotlin Concise - Drastically reduce the amount of boilerplate

    code you need to write. Safe - Avoid entire classes of errors such as null pointer exceptions. Versatile - Build server-side applications, Android apps or front-end code running in the browser.
  3. Kotlin in Expedia Android Kotlin code is at 23% and

    rising. Refactoring started mid 2015. Hotels, Packages, Flights, Services and MockWebServer & tests classes are 90% in Kotlin Cars/LX/Legacy tablet code still in java. Other teams in Expedia are experimenting with Kotlin in the web.
  4. Features • Null type and safety • Lambdas • Optional

    params • Data classes • Extension functions • Delegates • Smart Casting
  5. Kotlin Roadmap for Android • Incremental compilation • support for

    Jack and Jill toolchain • Instant run works for cold swaps right now not for hot swaps • Lint checks in Kotlin 1.0.2
  6. Defining Functions fun sum(a: Int, b: Int): Int {
 return

    a + b } fun sum(a: Int, b: Int) = a + b

  7. fun printSum(a: Int, b: Int): Unit {
 print(a + b)


    } fun printSum(a: Int, b: Int) {
 print(a + b)
 } Defining Functions
  8. fun doSomething(): Int {
 val a: Int = 1
 val

    b = 1 
 val c: Int 
 c = a + b
 
 return c
 } Defining local variables
  9. fun doSomething(): Int {
 val a: Int = 1
 var

    b = 1 val c: Int b += 5
 c = a + b
 
 return c
 } Defining local variables
  10. Using conditional expressions fun doSomething(a: Int, b: Int): Int {


    if (a > b)
 return a
 else
 return b
 }
  11. Using conditional expressions fun doSomething(a: Int, b: Int): Int {


    if (a > b)
 return a
 else
 return b
 } fun doSomething(a: Int, b: Int) = if (a > b) a else b

  12. Using a for loop fun doSomething(args: Array<String>) {
 for (arg

    in args)
 print(arg)
 } fun doSomething(args: Array<String>) {
 for (i in args.indices)
 print(args[i])
 }
  13. Using when expression fun doSomething(obj: Any) {
 when (obj) {


    1 -> print("One")
 "Hello" -> print("Kotlin")
 is Long -> print("Long")
 !is String -> print(“!string")
 else -> print("Unknown")
 }
 }
  14. Using ranges fun doSomething(x: Int, y: Int) {
 if (x

    in 1..y - 1)
 print("In")
 
 for (x in 1..5)
 print(“N") if (x !in 1..y - 1)
 print(“In") }
  15. Using ranges fun doSomething(x: Int, y: Int) {
 if (x

    in 1..y - 1)
 print("In")
 
 for (x in 1..5)
 print("N")
 
 if (x !in 1..y - 1)
 print(“In") 
 }
  16. Using ranges fun doSomething(x: Int, y: Int) {
 if (x

    in 1..y - 1)
 print("In")
 
 for (x in 1..5)
 print("N")
 
 if (x !in 1..y - 1)
 print(“In") 
 }
  17. Class in Java public class SomeClass {
 
 private String

    variable;
 private final String defaultVar;
 
 SomeClass(String variable) {
 this.variable = variable;
 this.defaultVar = "Java";
 }
 
 SomeClass(String variable, String defaultVar) {
 this.variable = variable;
 this.defaultVar = defaultVar;
 }
 } // Use new SomeClass("Kotlin", "Java");
 new SomeClass("Kotlin");
  18. Class in Kotlin class SomeClass(var variable: String, val defaultValue: String

    = "Java") {
 }
 // Use
 SomeClass("Kotlin", "Java")
 SomeClass("Kotlin")
  19. Lambdas //In Kotlin fun doSomething() {
 val items = ArrayList<String>()


    items.sortBy { it.length }
 } //In Java ArrayList<String> items = new ArrayList();
 Collections.sort(items, new Comparator<String>(){
 @Override
 public int compare(String s1, String s2) {
 return s1.length() - s2.length();
 }
 });
  20. //In Kotlin button.setOnClickListener {
 Toast.makeText(this, "Button",
 Toast.LENGTH_LONG).show()
 } //In Java

    button.setOnClickListener(new View.OnClickListener(){
 public void onClick(View v) {
 Toast.makeText(this.MainActivity, "Button",
 Toast.LENGTH_LONG).show();
 }
 });
  21. class Vehicle(var value: String) {
 }
 
 fun doSomething() {


    val type = Vehicle("Car")
 println("${type.value}")
 }
  22. class Vehicle(var value: String) {
 }
 
 fun doSomething() {


    val type = Vehicle("Car")
 println("${type.value}")
 }
  23. class Vehicle(var value: String) {
 }
 
 fun doSomething() {


    val type = Vehicle("Car")
 println("${type.value}")
 }
  24. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val type = Vehicle("Car")
 type.print()
 }
  25. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val type = Vehicle("Car")
 type.print()
 }
  26. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val types = listOf(
 Vehicle("Car"),
 Vehicle("Truck"),
 Vehicle("Bike"))
 
 }
  27. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val types = listOf(
 Vehicle("Car"),
 Vehicle("Truck"),
 Vehicle("Bike"))
 
 for (type in types) {
 type.print()
 }
 }

  28. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val types = listOf(
 Vehicle("Car"),
 Vehicle("Truck"),
 Vehicle("Bike"))
 
 types.forEach { type ->
 type.print()
 }
 }
  29. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val types = listOf(
 Vehicle("Car"),
 Vehicle("Truck"),
 Vehicle("Bike"))
 
 types.forEach { it.print() }
 }
  30. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 val types = listOf(
 Vehicle("Car"),
 Vehicle("Truck"),
 Vehicle("Bike"))
 
 types.forEach { it.print() }
 }
  31. class Vehicle(var value: String) {
 fun print() = println("$value")
 }


    
 fun doSomething() {
 listOf(
 Vehicle("Car"),
 Vehicle("Truck"),
 Vehicle("Bike")
 ).forEach { it.print() }
 }
  32. open class Vehicle(var value: String) {
 fun print() = println("$value")


    }
 
 class Car(var type: String) : Vehicle(type){
 }
 
 fun doSomething() {
 listOf(
 Car("Car"),
 Vehicle("Truck"),
 Vehicle("Bike")
 ).forEach{it.print()}
 }
  33. open class Vehicle(var value: String) {
 fun print() = println("$value")


    }
 
 class Car(var type: String) : Vehicle(type){
 }
 
 fun doSomething() {
 listOf(
 Car("Car"),
 Vehicle("Truck"),
 Vehicle("Bike")
 ).forEach{it.print()}
 }
  34. open class Vehicle(var value: String) {
 open fun print() =

    println("$value")
 }
 
 class Car(var type: String) : Vehicle(type){
 override fun print() = println("Yo, Its a $value")
 }
 
 fun doSomething() {
 listOf(
 Car("Car"),
 Vehicle("Truck"),
 Vehicle("Bike")
 ).forEach{it.print()}
 }
  35. open class Vehicle(var value: String) {
 open fun print() =

    println("$value")
 }
 
 class Car(var type: String) : Vehicle(type){
 override fun print() = println("Yo, Its a $value")
 }
 
 fun doSomething() {
 listOf(
 Car("Car"),
 Vehicle("Truck"),
 Vehicle("Bike")
 ).forEach{it.print()}
 }
  36. Nullability I call it my billion-dollar mistake. It was the

    invention of the null reference …. has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. -Sir Charles Antony Richard Hoare
  37. Null and type safety fun doSomething() {
 var a: String

    = "abc"
 a = null // compilation error
 }
  38. fun doSomething() {
 var a: String = "abc"
 a =

    null // compilation error
 
 var b: String? = "abc"
 b = null // ok
 } Null and type safety
  39. fun doSomething() {
 var a: String = "abc"
 
 var

    b: String? = "abc"
 b = null // ok
 
 val l = a.length
 
 } Null and type safety
  40. 
 fun doSomething() {
 var a: String = "abc"
 


    var b: String? = "abc"
 b = null // ok
 
 val l1 = a.length
 
 val l2 = b.length // error:variable 'b' can be null
 
 } Null and type safety
  41. Checking for null in conditions fun doSomething() {
 var a:

    String = "abc"
 
 var b: String? = "abc"
 b = null // ok
 
 val l1 = a.length
 
 val l = if (b != null) b.length else -1
 
 }
  42. Safe Calls fun doSomething() {
 var a: String = "abc"


    
 var b: String? = "abc"
 b = null // ok
 
 val l1 = a.length
 
 val l2 = b?.length 
 
 }
  43. Elvis Operator fun doSomething() {
 var a: String = "abc"


    
 var b: String? = "abc"
 b = null // ok
 
 val l1 = a.length
 
 val l = if (b != null) b.length else -1
 
 }
  44. fun doSomething() {
 var a: String = "abc"
 
 var

    b: String? = "abc"
 b = null // ok
 
 val l1 = a.length
 
 val l2 = b?.length ?: -1 
 }
  45. if (originLocation != null) {
 if (originLocation.hierarchyInfo != null) {


    if (originLocation.hierarchyInfo.airport != null) {
 if (originLocation.hierarchyInfo.airport.airportCode != null) {
 departureAirportCode = originLocation.hierarchyInfo.airport.airportCode;
 }
 }
 
 }
 }
 else {
 departureAirportCode = "";
 }
  46. val departureAirportCode = originLocation?.hierarchyInfo?.airport?.airportCode ?: ""
 if (originLocation != null)

    {
 if (originLocation.hierarchyInfo != null) {
 if (originLocation.hierarchyInfo.airport != null) {
 if (originLocation.hierarchyInfo.airport.airportCode != null) {
 departureAirportCode = originLocation.hierarchyInfo.airport.airportCode;
 }
 }
 
 }
 }
 else {
 departureAirportCode = "";
 }
  47. The !! Operator fun doSomething() {
 var a: String =

    "abc"
 
 var b: String? = "abc"
 b = null // ok
 
 val l1 = a.length
 
 val l2 = b!!.length 
 }
  48. Optional-params //In Java void foo(int p1, boolean p2) { 


    }
 
 void foo(int p1) {
 foo(1, false);
 }
 
 void foo() {
 foo(1, false);
 }
  49. Data class data class Traveler(val name: String?, val age: Int)

    Automatically implements: equals()/hashCode()
 toString() of the form "User(name=John, age=42)",
 copy() function
  50. val testTravlerJohn = Traveler(“John”, 42) val testTravlerJane = Traveler(“Jane”, 41)

    assertEquals(testTravlerJohn, testTravlerJane) Data class in Testing
  51. public class Traveler(String name, Int age) @Override
 public boolean equals(Object

    o) {
 if (this == o) {
 return true;
 }
 if (!(o instanceof Traveler)) {
 return false;
 }
 
 Traveler traveler = (Traveler) o;
 
 if (name != name) {
 return false;
 }
 if (age != traveler.age) {
 return false;
 } return true; }
  52. Extension Functions //In Java public class StrUtils {
 public static

    String encodeString(String str) {
 return str.replaceAll(" ", "_")
 }
 } String text = "Hello World";
 System.out.println(StrUtils.encodeString(text)); 

  53. Extension Functions //In Kotlin fun String.encodeSpaces(): String {
 return this.replaceAll("

    ", "_")
 } val text = "hello world"
 
 println(text.encodeSpaces())
  54. val list = listOf("E", "H", "Hello", "Hi", "I")
 val map

    = mapOf(Pair("A", 1), Pair("B", 2), Pair("C", 3))
 
 list.forEach { s ->
 s.length
 } "E, H, Hello, Hi, I"
 
 Kotlin Collections Extensions
  55. val list = listOf("E", "H", "Hello", "Hi", "I")
 val map

    = mapOf(Pair("A", 1), Pair("B", 2), Pair("C", 3))
 
 var count = 0
 list.forEachIndexed { i, s ->
 count += i
 s.length
 } 
 "E, H, Hello, Hi, I"
 

  56. val list = listOf("E", "H", "Hello", "Hi", "I")
 val map

    = mapOf(Pair("A", 1), Pair("B", 2), Pair("C", 3))
 
 list.filter { s ->
 s.contains("H")
 }
 "H, Hello, Hi"
 

  57. val list = listOf("E", "H", "Hello", "Hi", "I")
 val map

    = mapOf(Pair("A", 1), Pair("B", 2), Pair("C", 3))
 
 list.first { s ->
 s.startsWith("He")
 }
 "Hello"
 

  58. val list = listOf("E", "H", "Hello", "Hi", "I")
 val map

    = mapOf(Pair("A", 1), Pair("B", 2), Pair("C", 3))
 
 map.forEach { entry ->
 entry.value }
 "A, B, C"
  59. //In Java final int[] sponsoredIndexes = { 0, 50, 51

    };
 
 ArrayList<Property> sponsored = new ArrayList<Property>();
 ListIterator<Property> it = properties.listIterator();
 while (it.hasNext()) {
 Property prop = it.next();
 if (prop.isSponsored()) {
 it.remove();
 sponsored.add(prop);
 }
 }
 
 for (int i = 0; i < sponsored.size() && i < sponsoredIndexes.length; i++) {
 if (sponsoredIndexes[i] <= properties.size()) {
 properties.add(sponsoredIndexes[i], sponsored.get(i));
 }
 }
  60. //In Kotlin fun putSponsoredItemsInCorrectPlaces(hotelList: List<Hotel>): List<Hotel> {
 val (sponsored, nonSponsored)

    = hotelList.partition { it.isSponsoredListing }
 val firstChunk = sponsored.take(1)
 val secondChunk = nonSponsored.take(49)
 val thirdChunk = sponsored.drop(1)
 val rest = nonSponsored.drop(49)
 return firstChunk + secondChunk + thirdChunk + rest
 }
  61. //In Java Observable.just("Hello World")
 .map(new Func1<String, Object>() {
 
 @Override


    public Object call(String s) {
 return s + "!";
 }
 })
 .subscribe(new Subscriber<String>() {
 @Override
 public void onCompleted() {
 //Completion
 }
 
 @Override
 public void onError(final Throwable e) {
 //TODO : Handle error here
 }
 
 @Override
 public void onNext(final String s) {
 Log.e("Output",s);
 }
 }); Reative Java
  62. Flow sensitive typing //In Java @Override
 public void onBindViewHolder(RecyclerView.ViewHolder holder,

    int position) {
 if (holder.getItemViewType() != LOADING_VIEW) {
 ((ViewHolder) holder).updateHotel();
 }
 else if (holder.getItemViewType() != HOTEL_VIEW) {
 ((LoadingViewHolder) holder).loadView();
 }
 }

  63. Flow sensitive typing //In Kotlin override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position:

    Int) {
 when (holder) {
 is HotelCellViewHolder-> holder.updateHotel()
 is LoadingViewHolder -> holder.loadView()
 }
 }
  64. Delegates var p: String by Delegate() Properties using the delegate

    expression will have its get() and set() methods delegated to the expression. * lazy * observable * notNull
  65. val view: Presenter by lazy {
 var view = stub.inflate()

    as Presenter
 view
 } Delegates.lazy
  66. Delegates.notNull class Foo {
 var bar : Bar by Delegates.notNull()

    // type is now Bar
 
 init {
 val s = bar // Using before setting throws an IllegalStateException!
 bar = Bar()
 }
 }
  67. Custom delegate(KotterKnife) fun <T : View> ViewGroup.bindView(id: Int): ReadOnlyProperty<Any, T>

    = ViewBinding(this, id) private class ViewBinding<T : View>(val source: Any, val id: Int) : ReadOnlyProperty<Any, T> {
 private val lazy = Lazy<T>()
 
 override fun getValue(thisRef: Any, property: KProperty<*>): T = lazy.get {
 findView<T>(source, id)
 ?: throw IllegalStateException("View ID $id for '${property.name}' not found.")
 }
 } val mapView: MapView by bindView(R.id.map_view)