Walmyr Carvalho - Mobile Specialist da Loggi, fala sobre Kotlin no Android: desbravando as oportunidades de ponta a ponta! no Kotlin Community Summit 2018.
Saiba mais em https://eventos.imasters.com.br/kotlinsummit/
6. 2ª linguagem mais amada - StackOverflow Developer Survey 2018
bit.ly/2Mc6HMa
7. Kotlin
- Criada pela JetBrains e anunciada publicamente em 2012
- Open Source (Apache 2.0)
- Suporta compilação pra JVM, JS e nativo
- Null-safety por design
8. E como a gente pode usar Kotlin nas nossas aplicações?
53. O Anko é uma biblioteca que facilita o desenvolvimento de interfaces no
Android utilizando Kotlin, sem a necessidade de se escrever XMLs
(além de outras coisinhas a mais).
56. O Anko é divido em quatro macro-repositórios:
- anko-commons: Métodos comuns a todos ao Anko em geral
- anko-layouts: Bindings gerais de layouts gerais do Anko
- anko-coroutines: Callbacks para Anko layouts com Coroutines
- anko-sqlite: Helpers do Anko para SQLite
Além desses, existem repositórios para Views, ViewGroups
e Layouts variados, como CardView, RecyclerView e mais.
57. dependencies {
// Anko Commons
implementation "org.jetbrains.anko:anko-commons:$anko_version"
// Anko Layouts
// sdk15, sdk19, sdk21, sdk23 are also available
implementation "org.jetbrains.anko:anko-sdk25:$anko_version"
implementation "org.jetbrains.anko:anko-appcompat-v7:$anko_version"
// Coroutine listeners for Anko Layouts
implementation "org.jetbrains.anko:anko-sdk25-coroutines:$anko_version"
implementation "org.jetbrains.anko:anko-appcompat-v7-coroutines:$anko_version"
// Anko SQLite
implementation "org.jetbrains.anko:anko-sqlite:$anko_version"
}
build.gradle
60. verticalLayout {
editText {
hint = "Name"
}
editText {
hint = "Password"
}
}.applyRecursively { view -> when(view) {
is EditText -> view.textSize = 20f
}}
MainActivity.kt
61. Com o Anko também temos uma série de funções para a exibição de
componentes (como Dialogs, ProgressBars e Toasts),
uso de logging, uso de resources/dimensions e outros.
62. // Toasts
toast("Hey, I'm a toast!")
toast(R.string.message)
longToast("Wow, this is a nice summit!")
// Snackbars
snackbar(view, "Hey, I'm a snackbar!")
snackbar(view, R.string.message)
snackbar(view, "Action!", "Click me!") { doYourStuff() }
longSnackbar(view, "Wow, this is a nice summit!")
MainActivity.kt
65. O Kotlin Android Extensions (ou kotlinx) ajuda a evitar a necessidade de se
utilizar o findViewById(…) na hora de se instanciar Views no Android
(além de outras coisinhas a mais):
68. // Using R.layout.activity_main from the 'main' source set
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Instead of findViewById<TextView>(R.id.textView)
textView.setText("Hello, Kotlin Community Summit!”)
}
}
MainActivity.kt
69. Também é possível utilizar o annotation
@Parcelize para a criação de Parcelables:
73. Coroutines no Kotlin são threads "mais leves”, com uma sintaxe de código
assíncrono tão direta quanto a de um código síncrono, com o objetivo
de prover APIs simples para descomplicar operações assíncronas em geral.
76. Elas são tipos de funções chamadas suspending functions, e tem seus métodos
marcados com a palavra chave suspend:
77. // run the code on a background thread pool
fun asyncOverlay() = async(CommonPool) {
// start two async operations
val original = asyncLoadImage("original")
val overlay = asyncLoadImage(“overlay")
// apply the overlay with both callbacks
applyOverlay(original.await(), overlay.await())
}
// execute the coroutine on UI context
launch(UI) {
val image = asyncOverlay().await()
showImage(image)
}
78. O launch é a maneira mais simples de se criar uma coroutine numa thread em
background, tendo um Job (uma task, basicamente) como sua referência para si.
79. public actual fun launch(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> Unit
): Job
80. Conceitualmente, o async é similar ao launch,
mas a diferença deles é que o async retorna um Deferred,
que é basicamente uma future (ou promise).
81. public actual fun <T> async(
context: CoroutineContext = DefaultDispatcher,
start: CoroutineStart = CoroutineStart.DEFAULT,
parent: Job? = null,
block: suspend CoroutineScope.() -> T
): Deferred<T>
82. O CoroutineContext diz respeito a qual thread ela irá rodar: background
(CommonPool) ou UI.
83. Tecnicamente, um Deferred é um Job, só que com uma future com uma
promessa de entregar um valor em breve.
84. Ou seja: No async você tem a mesma funcionalidade do launch, mas com
a diferença que ele retorna um valor no .await():
85. fun getUser(userId: String): User = async {
// return User
}
launch(UI) {
val user = getUser(id).await()
navigateToUserDetail(user)
}
86. Também é possível rodar alguma operação bloqueando
completamente a thread, utilizando o runBlocking:
88. Também é possível cancelar um Job (ou um Deferred<T>)
e checar o estado dele, se eu quiser:
89. val job = launch {
// do your stuff
}
job.cancel()
val job = launch {
while (isActive){
//do your stuff
} }
90. Resumindo:
Se eu não preciso de um callback explícito -> launch
Se eu preciso esperar uma future (Deferred) -> async
Se eu preciso bloquear minha thread -> runBlocking
103. // Instead of this:
lateinit var calculator: Calculator
beforeEachTest {
calculator = Calculator()
}
// You can do:
val calculator by memoized { Calculator() }
104. object CalculatorSpec: Spek({
describe("A calculator") {
val calculator by memoized { Calculator() }
describe("addition") {
it("returns the sum of its arguments") {
assertThat(3, calculator.add(1, 2))
}
}
}
})
CalculatorSpec.kt
106. O MockK é um biblioteca de mock otimizada para Kotlin e com diversas
features interessantes como DSLs, suporte a annotations,
argument capturing e outras.
109. val car = mockk<Car>()
every { car.drive(Direction.NORTH) } returns Outcome.OK
car.drive(Direction.NORTH) // returns OK
verify { car.drive(Direction.NORTH) }
110. @ExtendWith(MockKExtension::class)
class CarTest {
@MockK
lateinit var car1: Car
@RelaxedMockK
lateinit var car2: Car
@MockK(relaxUnitFun = true)
lateinit var car3: Car
@SpyK
var car4 = Car()
@Test
fun calculateAddsValues1() {
// ... use car1, car2, car3 and car4
}
}
113. Mais importante do que sair utilizando todas essas bibliotecas
é realmente entender como elas funcionam, como são construídas
e tentar levar as boas ideias para sua rotina. "