Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Turbinando o desenvolvimento Android com Kotlin

901 views

Published on

Slides da minha palestra sobre Kotlin apresentada nos seguintes eventos:
- GDG Tech Tour Caruaru: I/O Recap - 22/07/2017
- Google Launchpad Build PoA - 05/08/2017
- Androidos - 12/08/2017
- Google Agency Day SP - 16/08/2017
- DevFest Maceió - 23/09/2017

Published in: Software
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Turbinando o desenvolvimento Android com Kotlin

  1. 1. Turbinando o desenvolvimento Android com Kotlin +Nelson Glauber @nglauber
 www.nglauber.com.br
  2. 2. Porque Kotlin? • Linguagem moderna, concisa, intuitiva e fácil de aprender. • Open Source, mantido pela JetBrains • 100% Interoperável com Java. Você pode possuir código Java e Kotlin no mesmo projeto. • Suporte nativo no Android Studio. • Menos verboso. Você escreve menos código. • Null Safety • Possui recursos de linguagens funcionais • Extension functions, funções de alta ordem e muito mais
  3. 3. build.gradle buildscript { ext.kotlin_version = '1.1.3-2' repositories { jcenter() } dependencies { classpath ‘com.android.tools.build:gradle:2.3.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }
  4. 4. apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { ... sourceSets { main.java.srcDirs += 'src/main/kotlin' } } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" ... } ... build.gradle
  5. 5. Kotlin bytecode? data class Person( var name: String, var age: Int) { override fun toString(): String { return "$name - $age" } } Person.kt Compiler
 kotlinc ________________ ________________ ________________ ________________ ________________ ________________ ________________ Person.class
  6. 6. val (imutável) var (mutável) val hello: String = "hello" val world = "world" println("$hello $world") world = "bla" // compilation error var helloWorld: String = "Hello" helloWorld = "Hello World" println(helloWorld)
  7. 7. Tipos de dados val i: Int = 7 // no automatic conversion val d: Double = i.toDouble() var c: Char = 'c' val s = "Example" c = s[2] // Char 'a' val i1: Int = c.toInt() val i2 = 12 // Int val iHex = 0x0f // Int em hexadecimal val l = 3L // Long val d1 = 3.5 // Double val f = 3.5F // Float val any: Any = 3 // Any=Object * Não existem tipos primitivos
  8. 8. Range val x = 5 if (IntRange(1, 10).contains(x)) { // do something } if (1.rangeTo(10).contains(x)) { // do something } if ((1..10).contains(x)) { // do something }
  9. 9. if/else e when 
 podem retornar valores val max = if (a > b) a else b val msg = when (x) { in 1..10, 100 -> "x is in the range or is 100” in validNumbers -> "x is valid" !in 10..20 -> "x is outside the range" else -> "none of the above" }
  10. 10. try/catch também… val content = try { // load some data from file return fileContent } catch (e: Exception) { return null } Importante! Kotlin não possui checked exceptions!
  11. 11. for for (item in list) { //... iterate over a list } for (i in 0..NUM_ROWS) { //... i == NUM_ROWS } for (i in 0 until NUM_ROWS) { //... i < NUM_ROWS } for (i in NUM_ROWS downTo 0) { //... from NUM_ROWS to 0 } for (i in 0..10 step 2) { //... 0, 2, 4, 6, 8, 10 }
  12. 12. Métodos ou Funções? // void = Unit fun foo(text: String) : Unit { println("Hi $text") } fun bar(text: String) { println("Hey $text") } // more verbose method fun sum1(x: Int, y: Int) : Int { return x + y } // or simpler... fun sum2(x:Int, y:Int): Int = x + y // even simpler fun sum3(x:Int, y:Int) = x + y
  13. 13. Parâmetros com valores padrão fun showMessage(title : String = "Hello", name : String = "Glauber") { println("$title $name") } // We can call this function using… showMessage() showMessage("Hey") showMessage("Hello", "Nelson") showMessage(name="José")
  14. 14. val employee = Employee("Nelson", 35, "99009900") print("${employee.name} - " + "${employee.age} / ${employee.id}") Classes open class Person(var name : String, var age : Int) class Employee(name : String, age : Int, var id : String) : Person(name, age)
  15. 15. Classes open class Person { var name : String = "" var age : Int = 0 } class Employee(name : String, age : Int, var id : String) : Person() { init { this.name = name this.age = age } } val employee = Employee("Nelson", 35, "99009900") print("${employee.name} - " + "${employee.age} / ${employee.id}")
  16. 16. Classes class Company { init { // Initialize some stuff... } constructor(name : String) { // Initialize with name } constructor(id : Int) { // Initialize with ID } }
  17. 17. Data Classes data class Product(var name: String, var descr: String, var price: Float) • Já possui as funções equals()/ hashCode() • Já possui toString() no padrão
 "Product(name=A, descr=B, price=42)” • Já possui o método copy() • destructuring functions correspondentes as propriedades ordenadas por declaração • Não pode ser estendida p1 = Product("X", "Y", price = 10F) p2 = p1.copy(price = 20F) val (name, _, price) = p1 var p1 = Product("X", "Y", price = 10F) var p2 = Product("X", "Y", price = 10F) println(p1 == p2) // true println(p1 === p2) // false
  18. 18. Interfaces interface Foo { val value : Int // must implement getter fun sum(x : Int, y : Int) = x + y // default implementation }
  19. 19. Modificadores de acesso • public (padrão) • private • protected = private + subclasses
 classes no mesmo pacote não acessam • internal • Não possui o modificador para package 😢
  20. 20. Properties class Person { var name : String = "" get() = field.toUpperCase() set(value) { field = "Name: $value" } var age : Int = 0 }
  21. 21. Companion Object int x = Foo.Companion.getCONSTANT_1(); int y = Foo.CONSTANT_2; Person p = Foo.ROOT; Foo.foo(); ☕ companion object { val CONSTANT_1 = 1 // private + getter const val CONSTANT_2 = 2 // public @JvmField val ROOT = User("root”) // getROOT() @JvmStatic fun foo() {} }
  22. 22. Classes x Tipos Class Type String Yes Yes String? No Yes Person Yes Yes Person? No Yes String? String
  23. 23. Null Safety // Compilation error var person: Person = null // Now can be null var personOpt: Person? = null // Compilation error println(pessoaOpt.nome) // It works! println(pessoaOpt?.nome)
  24. 24. Null Safety // you can avoid the "?." Operator with a "if" if (pessoaOpt != null) { println(pessoaOpt.nome) } // Smell... println(pessoaOpt!!.nome) // Elvis still alive val name = pessoaOpt?.nome ?: "empty"
  25. 25. Late Init class MainActivity : AppCompatActivity() { private lateinit var db: BookDatabase ... Relaxa compilador, eu vou inicializar esse atributo depois. 
 Confia em mim! 😎
  26. 26. Cast val text1 = param as String // may throw an exception val text2 = param as? String // this is may be null ... if (param is String) { val text = param // smart cast!! ... }
  27. 27. Null Safety • Como conseguir um NullPointerException? • Lançando a exceção explicitamente • Usando o operador !! • Acessando um atributo lateinit que não foi inicializado • Invocando código Java 😈
  28. 28. Extension Functions fun String.withPlusInTheEnd() : String = this + "+" "Glauber".withPlusInTheEnd() fun Activity.showShortToast(text: String) { Toast.makeText(this, text, Toast.LENGTH_SHORT).show() }
  29. 29. Extension Properties val <T> List<T>.lastIndex: Int get() = size - 1
  30. 30. apply, with, let, run • apply é uma extension function que executa o bloco de código sobre uma instância e retorna a própria instância.  • with  não é uma extension function e o objeto deve ser explicitamente passado como parâmetro. O returno é o resultado do bloco da função.
  31. 31. apply, with, let, run startActivity(Intent(activity, DetailActivity::class.java).apply { putExtra("nome", "Glauber") putExtra("idade", 33) }) with(person) { name = "Glauber" age = 33 }
  32. 32. apply, with, let, run • let é uma função de escopo muito usado para lidar com nullable objects. Ao invés de encadear if-else, você pode simplesmente combinar o operador "?." com o let. Teremos então um lambda onde o argumento é uma versão not-nullable do objeto original.Por fim, o let retorna o resultado do bloco. • run é uma extension function e é algo como uma junção do let e apply, A única diferença é o retorno: o apply retorna o próprio objeto, enquanto que o run retorna o resultado do bloco.
  33. 33. apply, with, let, run val person : Person? = intent.getSerializableExtra("person") as? Person person?.let { listOfPerson.add(person) listOfPerson.sortBy { it.name } adapter.notifyDataSetChanged() } val x = Person("Nelson", 33).run { name.length + age } println(x) // 39
  34. 34. Synthetic Imports import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) textViewMessage.text = "Hello world!" } ... apply plugin: 'kotlin-android-extensions' Override
 obrigatório
  35. 35. Lambdas // Verbose fabAdd.setOnClickListener(object : View.OnClickListener { override fun onClick(v: View?) { } }) // Concise fabAdd.setOnClickListener { view -> } opcional
  36. 36. Lambdas listView.setOnItemClickListener { _, _, position, _ -> showShortToast(listOfPerson[position].name) }
  37. 37. Higher-Order Functions class PersonAdapter(val people: List<Person>, val callback: (Person) -> Unit) : RecyclerView.Adapter<PersonHolder>() { override fun onBindViewHolder(holder: PersonHolder?, position: Int) { val person = people[position] holder?.textView?.apply { text = person.name setOnClickListener { callback(person) } } }
  38. 38. Higher-Order Functions override fun onCreate(savedInstanceState: Bundle?) { ... var adapter = PersonAdapter(peopleList, this::onItemClick) ... } private fun onItemClick(person : Person) { showShortToast(person.name) } override fun onCreate(savedInstanceState: Bundle?) { ... var adapter = PersonAdapter(peopleList, { person -> }) ... }
  39. 39. Typealias typealias PersonCallback = (Person)->Unit class PersonAdapter(val people: List<Person>, val callback: PersonCallback) : RecyclerView.Adapter<PersonHolder>() {
  40. 40. Operator overloading +a a.unaryPlus() -a a.unaryMinus() !a a.not() a++ a.inc() a— a.dec() a += b a.plusAssign(b) a -= b a.minusAssign(b) a *= b a.timesAssign(b) a /= b a.divAssign(b) a %= b a.modAssign(b) a + b a.plus(b) a - b a.minus(b) a * b a.times(b) a / b a.div(b) a % b a.rem(b) a..b a.rangeTo(b) a in b a.contains(b) a > b a.compareTo(b) > 0 a < b a.compareTo(b) < 0 a >= b a.compareTo(b) >= 0
  41. 41. Operator overloading operator fun String.times(b: Int): String { val buffer = StringBuffer() for (i in 1..b) { buffer.append(this) } return buffer.toString() } val newString = "Test" * 4
  42. 42. Delegated Properties class SomeClass { var p: String by Delegate() } // ... import kotlin.reflect.KProperty class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } }
  43. 43. Lazy, Observable, Vetoable val people: MutableList<Person> by lazy { mutableListOf<Person>() } class User { var email: String by Delegates.observable("") { prop, old, new -> //handle the change from old to new value } } var positiveNumber = Delegates.vetoable(0) { d, old, new -> new >= 0 }
  44. 44. Mapeando um objeto com um Map class User(map: Map<String, Any?>) { val name: String by map val age: Int by map } val user = User(mapOf( "name" to "John Doe", "age" to 25 ))
  45. 45. Collections 😍 val list = listOf(1, 2, 3, 4, 5) println(list[1]) val mutList = mutableListOf<Int>() mutList.add(1) val array = arrayOf("Nelson", "Glauber") println(array[0]) val map = mapOf(1 to "Glauber", 2 to "Nelson", Pair(3, "Chico")) println(map[1]) val mutMap = mutableMapOf<Int, String>() mutMap.put(1, "João")
  46. 46. Collections 😍 • Agregate • any, all, count, forEach, forEachIndexed, max, min, none, sumBy, … • Filtering • filter, filterNot, slice, take, takeLast, takeWhile, … • Mapping • flatMap, map, groupBy, mapIndexed, …
  47. 47. Collections 😍 • Elements • contains, elementAt, first, indexOf, last, lastIndexOf, single, … • Generation operations • merge, partition, plus, zip e unzip • Ordering • reverse, sort, sortBy, sortDescending e sortDescendingBy
  48. 48. Collections 😍 val pessoas = listOf( Pessoa("Nelson", 33), Pessoa("Glauber", 33), Pessoa("Ana", 27), Pessoa("João", 12) ) val p1 = pessoas.sortedBy { it.idade } p1.forEach { println(it) } val p2 = pessoas.maxBy { p -> p.idade } println(p2) val people = pessoas.groupBy { it.idade } println("agrupado por idade: $people")
  49. 49. Collections 😍 // Return the set of cities the customers are from fun getCitiesCustomersAreFrom(): Set<City> = customers.map { customer -> customer.city }.toSet() // Return a list of the customers who live in the given city fun getCustomersFrom(city: City): List<Customer> = customers.filter { customer -> customer.city == city }
  50. 50. Singletons com Object object SilvioSantos { fun mahOeee() = "Mah Ôeeee!" fun juizo() = false } SilvioSantos.mahOeee() if (SilvioSantos.juizo()) println("sem graça :(") else println("Processo :’(")
  51. 51. infix • Notação para chamada de funções sem a necessidade de usar “.” ou “( )” • Devem ser "métodos" de uma classe ou extension function. • Só podem possuir um parâmetro // Define extension to Int infix fun Int.shl(x: Int): Int { ... } /* call extension function using infix notation */ 1 shl 2 // is the same as 1.shl(2)
  52. 52. Sealed classes sealed class Operation { class Add(val value: Int) : Operation() class Substract(val value: Int) : Operation() class Multiply(val value: Int) : Operation() class Divide(val value: Int) : Operation() } fun execute(x: Int, op: Operation) = when (op) { is Operation.Add -> x + op.value is Operation.Substract -> x - op.value is Operation.Multiply -> x * op.value is Operation.Divide -> x / op.value }
  53. 53. Coroutines + Anko async(UI) { val books = bg { loadBooksAsync() } updateListView(books.await()) } dependencies { compile "org.jetbrains.anko:anko-coroutines:$anko_version" } // gradle.properties
 kotlin.coroutines=enable
  54. 54. Curiosidades • Você pode nomear seus imports usando “as" • Você pode ter funções dentro de funções • Você pode ter funções soltas em um arquivo, nesse caso, será gerada uma classe com o nome do arquivo, isso pode ser alterado usando @file:JvmName(“SuaClasse”) import com.mycompany.data.local.entity.Trip import com.mycompany.model.Trip as TripModel
  55. 55. A IDE dá aquela forcinha… • Aponta os erros e melhorias • Ctrl-V de código Java faz a conversão automática para Kotlin • Ver bytecode do Kotlin e ver o Java
  56. 56. Prós • Linguagem moderna, repleta de recursos e facilidades não disponíveis no Java • Suporte nativo do Android Studio. • É muito fácil converter um código Java para Kotlin. • Java e Kotlin podem co-existir no mesmo projeto. • Não há overhead significante de performance do Kotlin em comparação com o Java.
  57. 57. Contras • A std library do Kotlin adicionará aproximadamente 300KB ao seu APK. • Autocomplete demora um pouco mais. • Compilação demora um pouco mais.
  58. 58. Learn more… • Site Oficial (kotlinlang.org) • Editor on-line (try.kotlinlang.org) • Kotlin Koans (try.kotlinlang.org/koans) • Antonio Leiva’s book (antonioleiva.com/google-kotlin) • Como eu aprendi Kotlin (bit.do/nglauber_kotlin) • Dominando o Android com Kotlin (em breve) 😉
  59. 59. Dúvidas?
  60. 60. @nglauber +NelsonGlauber www.nglauber.com.br

×