SlideShare a Scribd company logo
CRIANDO APP ANDROID UTILIZANDO KOTLIN
Luiz Santana / André Cardoso
QUAL É O PROBLEMA?
- Java 8 no Android N
- Streams
- API level 23 ou RxJava
- Lambdas, referências à métodos, non-capturing
- API level 23 ou Retrolambda
- Try with resources
- API level 19 ou Retrolambda
- Métodos default em interfaces
- API level 23
Android Moderninho
- Não dá pra adicionar métodos à tipos existentes
- *Util em todo lugar
- Nulls
- NPEs em todo lugar
- Java é verboso
- APIs do Android são complexas
- Herança e nulls em todo lugar
Limitações do Java no Android
KOTLIN?
- JetBrains
- JVM
- Concisa, Segura, Versátil, Interoperável
package hello



fun main(args: Array<String>) {

println("Hello TDC!")

}
fun welcome(name: String, event: String): String {

return "Hello ${name}, welcome to ${event}!"

}
Functions
fun welcome(name: String, event: String) =
"Hello ${name}, welcome to ${event}!"
Functions
fun main(args: Array<String>) {

val greeting = welcome("André", "TDC")

println(greeting)

}
Functions
fun main(args: Array<String>) {

val greeting = welcome("André", "TDC")

println(greeting)



greeting = welcome("Luiz", "TDC")

println(greeting)

}
Variáveis
fun main(args: Array<String>) {

var greeting = welcome("André", "TDC")

println(greeting)



greeting = welcome("Luiz", "TDC")

println(greeting)

}
Variáveis
fun welcome(name: String, event: String = "TDC")

= "Hello ${name}, welcome to ${event}!"



Parâmetros Default
fun main(args: Array<String>) {

val greeting = welcome("André")

println(greeting)

}
Parâmetros Default
fun main(args: Array<String>) {

val greeting = welcome(name = "Luiz", event = "I/O")

println(greeting)

}
Parâmetros Default
fun welcome(name: String = "Developer", event: String = "TDC")

= "Hello ${name}, welcome to ${event}!"



Parâmetros Default
fun main(args: Array<String>) {

val greeting = welcome(event = “Android Meetup")

println(greeting)

}
Parâmetros Default
fun main(args: Array<String>) {

val greeting = welcome()

println(greeting)

}
Parâmetros Default
val lyrics = """

|Jamais a natureza

|Reuniu tanta beleza

|Jamais algum poeta

|Teve tanto pra cantar!

“"".trimMargin()
println(lyrics)



val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"

var datePattern = """d{2} ${month} d{4}"""



val today = "13 MAY 2016".matches(Regex(datePattern))

println(today)
String Templates
val famousPeople = arrayListOf<String>("Einstein", "Newton", "MC Biel")



val forSure = famousPeople is java.util.ArrayList

println(forSure)
Collections
val famousPeople = arrayListOf<String>("Einstein", "Newton", "MC Bin Laden")



val pairs = famousPeople.map { Pair(it, it == "MC Bin Laden") }



pairs.forEach {

val (name, singer) = it

val verb = if (singer) "is" else "is not"

println("${name} ${verb} a singer")

}
Lambdas
val pairs = famousPeople.map { Pair(it, it == "MC Bin Laden") }
Equality
pairs.forEach {

val (name, singer) = it

val verb = if (singer) "is" else "is not"

println("${name} ${verb} a singer")

}
Destructors e if expressions
fun String.isSinger() = this == "MC Bin Laden"
Extension Functions
val famousPeople = arrayListOf<String>("Einstein", "Newton", "MC Bin Laden")



famousPeople.forEach {

val verb = if (it.isSinger()) "is" else "is not"

println("${it} ${verb} a singer")

}
Extension Functions
fun SQLiteDatabase.transaction(code: SQLiteDatabase.() -> Unit) {

try {

beginTransaction()

code()

setTransactionSuccessful()

} catch (e: TransactionAbortException) {

// Do nothing, just stop the transaction

} finally {

endTransaction()

}

}



fun SQLiteDatabase.delete(tableName: String, whereClause: String =
"", vararg args: Pair<String, Any>): Int {
…

}
Extension Functions
db.transaction {

db.delete("people", "is_singer = ?", "is_singer" to true)

}
Extension Functions
fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {

val email = client?.personalInfo?.email ?: "someone@isgoingtoreadit.com"

if (message != null) {

mailer.sendMessage(email, message)

}

}
Tipos Null
fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {

val email = client?.personalInfo?.email ?: "someone@isgoingtoreadit.com"

if (message != null) {

mailer.sendMessage(email, message)

}

}
Null Safe Calls
fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {

val email = client?.personalInfo?.email ?: "someone@isgoingtoreadit.com"

if (message != null) {

mailer.sendMessage(email, message)

}

}
Elvis
fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {

val email = client?.personalInfo?.email ?: "someone@isgoingtoreadit.com"

if (message != null) {

mailer.sendMessage(email, message)

}

}
Smart Cast
fun eval(expr: Expr): Int =

when (expr) {

is Num -> expr.value

is Sum -> eval(expr.left) + eval(expr.right)

else -> throw IllegalArgumentException("Unknown expression")

}



interface Expr

class Num(val value: Int) : Expr

class Sum(val left: Expr, val right: Expr) : Expr
Smart Cast
class Person constructor(name: String) {

}



class Singer(name: String, isSinger: Boolean) : Person(name) {

}
Classes
open class Person constructor(name: String) {

}



class Singer(name: String, isSinger: Boolean) : Person(name) {

}
Classes
open class Person constructor(name: String) {

open fun walk() {

println("walking as a normal person")

}

}



class Singer(name: String, isSinger: Boolean) : Person(name) {

override fun walk() {

println("walking with some style")

}

}
Classes
interface Funk {

var views: Long



fun funk() {

views++

println("ta tranquilo ta favorável")

}

}
class Singer(name: String, isSinger: Boolean, override var views:
Long) : Funk
Interfaces
fun main(args: Array<String>) {

val mc = Singer("MC Bin Laden", true)

mc.funk()

mc.walk()

}
Interfaces
interface Moveable {

fun move() { print("move") }

}



interface Walkable {

fun move() { walk() }

fun walk() { print("walk") }

}



class Human : Moveable, Walkable {

override fun move() {

super<Walkable>.move()

}

}
Interfaces - Resolução de conflitos
data class Singer(val name: String, val isSinger: Boolean, override var
views: Long) : Funk
fun main(args: Array<String>) {

val mc = Singer("MC Bin Laden", isSinger = true, views = 10000000)

println(mc.toString())

println(mc.hashCode())

println(mc.copy(name = "Catra"))

}
Singer(name=MC Bin Laden, isSinger=true, views=10000001)
-117390027
Singer(name=Catra, isSinger=true, views=10000001)
Data class
class Panelist {

val presentation : String by lazy {

"Kotlin!!!!"

}



var numberOfQuestions : Int by Delegates.observable(0) {

prop, old, new ->

println("It was ${old} not it is ${new}")

}

}
Delegated properties
Criando app Android utilizando Kotlin
CRIANDO O APP
CRIANDO O APP | OBJETIVO
- Criar um app em Kotlin
- Consumir dados MOCK, simulando
“News feed” do Reddit
CRIANDO O APP | PRIMEIRO PASSO
- Criar projeto com Activity básica
- Instalando Plugin:
- Preferences
- Plugins
- Buscar por “Kotlin”
CRIANDO O APP | PLUGIN
CRIANDO O APP | CONFIGURANDO
- Abrir painel de ações
- ctrl + shift + A
- cmd + shift + A
O QUE MUDOU?
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'



android {

…

sourceSets {

main.java.srcDirs += 'src/main/kotlin'

}

}



dependencies {
…

compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

}

buildscript {

ext.kotlin_version = '1.0.1-2'

repositories {

mavenCentral()

}

dependencies {

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

}

}

build.gradle
JAVA -> KOTLIN
public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

setSupportActionBar(toolbar);



FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

fab.setOnClickListener(new OnClickListener(…) {
…
});

}



@Override

public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.menu_main, menu);

return true;

}
…
}
MainActivity.java
Java -> Kotlin | CONVERTENDO
- Convertendo código
- Abrir painel ação
- Buscar por “Convert Java…”
E A MÁGICA ACONTECE…
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener({ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}



override fun onCreateOptionsMenu(menu: Menu): Boolean {

menuInflater.inflate(R.menu.menu_main, menu)

return true

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
…

MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
…

MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
…

MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
…

MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?)
{

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
…

MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener({ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}



override fun onCreateOptionsMenu(menu: Menu): Boolean {

menuInflater.inflate(R.menu.menu_main, menu)

return true

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {

…

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener(

{ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {

…

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener(

{ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {

…

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener(

{ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {

…

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener(

{ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {

…

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener(

{ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}
…

}
MainActivity.kt
class MainActivity : AppCompatActivity() {



override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

val toolbar = findViewById(R.id.toolbar) as Toolbar?

setSupportActionBar(toolbar)



val fab = findViewById(R.id.fab) as FloatingActionButton?

fab?.setOnClickListener({ view -> Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })

}



override fun onCreateOptionsMenu(menu: Menu): Boolean {

menuInflater.inflate(R.menu.menu_main, menu)

return true

}
…

}
MainActivity.kt
Criando o App | APP RODANDO
CRIANDO UM FRAGMENT
FRAGMENT | MUDANÇAS
- Adicionado Fragment Management
- Removido Float Button
- Removido Option Menu
FRAGMENT | LAYOUT
- Criando um layout Simples
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“….”

android:layout_width="match_parent"

android:layout_height="match_parent">



<android.support.v7.widget.RecyclerView

android:id="@+id/news_list"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</android.support.v7.widget.RecyclerView>


</RelativeLayout>
FRAGMENT | KOTLIN CODE
class NewsFragment : Fragment() {

private var newsList: RecyclerView? = null



override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, 

savedInstanceState: Bundle?): View? {

val view = inflater?.inflate(R.layout.fragment_news, container, false)

newsList = view?.findViewById(R.id.news_list) as RecyclerView?

newsList?.setHasFixedSize(true)

newsList?.layoutManager = LinearLayoutManager(context)



return view

}

}
FRAGMENT | KOTLIN CODE
class NewsFragment : Fragment() {

private var newsList: RecyclerView? = null



override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, 

savedInstanceState: Bundle?): View? {

val view = inflater?.inflate(R.layout.fragment_news, container, false)

newsList = view?.findViewById(R.id.news_list) as RecyclerView?

newsList?.setHasFixedSize(true)

newsList?.layoutManager = LinearLayoutManager(context)



return view

}

}
Como melhorar

o código?
EXTENSION FUNCTIONS
EXTENSION FUNCTIONS | INFLATE
Como fazer o código abaixo ficar mais intuitivo?
…

val view = inflater?.inflate(R.layout.fragment_news, container, false) 

…
…

val view = container?.inflate(R.layout.fragment_news) 

…
EXTENSION FUNCTIONS | INFLATE
Como implementar?
// ExtensionsKt.kt



fun ViewGroup.inflate(layoutId : Int) : View {

return LayoutInflater.from(context).inflate(layoutId, this, false)

}
EXTENSION FUNCTIONS | INFLATE
Reuso do código
// Java

ExtensionsKt.inflate(container, R.layout.news_fragment);

// Kotlin

container?.inflate(R.layout.fragment_news)
@file:JvmName("ExtensionsUtils")

package com.arctouch.kotlin.commons.extensions

…

// Usar assim em Java:
ExtensionsUtils.inflate(container, R.layout.news_fragment);
EXTENSION FUNCTIONS | INFLATE
Parâmetros com valor padrão
fun ViewGroup.inflate(layoutId : Int, attachToRoot : Boolean = false) : View {

return LayoutInflater.from(context).inflate(layoutId, this, attachToRoot)

}



// usar assim
val view = container?.inflate(R.layout.fragment_news) // default: false


// ou assim

val view = container?.inflate(R.layout.fragment_news, true)
ANDROID EXTENSIONS
ANDROID EXTENSIONS | ADICIONANDO
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'
Adicionar no build.gradle
ANDROID EXTENSIONS | FUNCIONALIDADE
- Voltando ao Layout do Fragment…
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“….”

android:layout_width="match_parent"

android:layout_height="match_parent">



<android.support.v7.widget.RecyclerView

android:id="@+id/news_list"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

</android.support.v7.widget.RecyclerView>


</RelativeLayout>
ANDROID EXTENSIONS | FUNCIONALIDADE
// importar no código
// import kotlinx.android.synthetic.<MODULO>.<VIEW>.*
import kotlinx.android.synthetic.main.fragment_news.*
// código antigo

newsList = view?.findViewById(R.id.news_list) as RecyclerView?

newsList?.setHasFixedSize(true)

newsList?.layoutManager = LinearLayoutManager(context)



// código novo

news_list.setHasFixedSize(true)

news_list.layoutManager = LinearLayoutManager(context)
LAZY PROPERTIES
LAZY PROPERTIES | INTRO
private val newsList by lazy {

news_list

}
override fun onActivityCreated(savedInstanceState: Bundle?) {

super.onActivityCreated(savedInstanceState)



newsList.setHasFixedSize(true) // Executado de maneira Lazy

newsList.layoutManager = LinearLayoutManager(context)

}

}
CRIANDO ADAPTER
CRIANDO ADAPTER | INICIO
- Usaremos padrão DelegateAdapter
- A ideia é ter diferentes tipos de view
num mesmo adapter
- Neste caso teremos algo parecido com:
CRIANDO ADAPTER | ESTRUTURA
- Cada ViewItem possui um ViewType
enum class ViewType {

LOADING,

NEWS

}
interface ViewDelegate {

fun getType() : ViewType

}
CRIANDO ADAPTER | O ADAPTER
- Nosso NewsAdapter


class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {



private val items: ArrayList<ViewItem> = ArrayList()
// outros métodos…

}
CRIANDO ADAPTER | O ADAPTER
- Nosso NewsAdapter


class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {



private val items: ArrayList<ViewItem> = ArrayList()

private val delegateAdapters: HashMap<ViewType,

ViewTypeDelegateAdapter> = HashMap()

// outros métodos…

}
CRIANDO ADAPTER | O ADAPTER
- Nosso NewsAdapter


class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {



private val items: ArrayList<ViewItem> = ArrayList()

private val delegateAdapters: HashMap<ViewType, ViewTypeDelegateAdapter>
= HashMap()



init {

delegateAdapters.put(ViewType.LOADING, LoadingDelegateAdapter())

}
// outros métodos…

}
CRIANDO ADAPTER | O ADAPTER
- Nosso NewsAdapter


class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {



private val items: ArrayList<ViewItem> = ArrayList()

private val delegateAdapters: HashMap<ViewType, ViewTypeDelegateAdapter> = HashMap()

private val loadingItem = object : ViewItem {

override fun getType() : ViewType = ViewType.LOADING

}



init {

delegateAdapters.put(ViewType.LOADING, LoadingDelegateAdapter())

items.add(loadingItem)

}
// outros métodos…

}
DATA CLASSES
DATA CLASSES | MODEL
- Clássico Java model
public class RedditNewsItem {

private String author;

private String title;



public RedditNewsItem(String author, String title) {

this.author = author;

this.title = title;

}



public String getAuthor() {

return author;

}



public void setAuthor(String author) {

this.author = author;

}



public String getTitle() {

return title;

}



public void setTitle(String title) {

this.title = title;

}

}
DATA CLASSES | MODEL
- Kotlin data class
data class RedditNewsItem(var author: String, var title: String)


Java Model + 

equals/hashCode 

toString

copy

DELEGATE ADAPTERS
DELEGATE ADAPTERS | ESTRUTURA
- Criando estrutura inicial
interface ViewTypeDelegateAdapter {

fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder

fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType)

}
DELEGATE ADAPTERS | LOADING
LoadingDelegateAdapter.kt
class LoadingDelegateAdapter : ViewTypeDelegateAdapter {



override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder

= SpinnerViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }



class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {

// infla layout em cima do pai

}

}
DELEGATE ADAPTERS | LOADING
LoadingDelegateAdapter.kt
class LoadingDelegateAdapter : ViewTypeDelegateAdapter {



override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder

= SpinnerViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }



class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {

// infla layout em cima do pai

}

}
DELEGATE ADAPTERS | LOADING
LoadingDelegateAdapter.kt
class LoadingDelegateAdapter : ViewTypeDelegateAdapter {



override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder

= SpinnerViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }



class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {

// infla layout em cima do pai

}

}
DELEGATE ADAPTERS | LOADING
LoadingDelegateAdapter.kt
class LoadingDelegateAdapter : ViewTypeDelegateAdapter {



override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder

= SpinnerViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }



class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {

// infla layout em cima do pai

}

}
DELEGATE ADAPTERS | LOADING
LoadingDelegateAdapter.kt
class LoadingDelegateAdapter : ViewTypeDelegateAdapter {



override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder

= SpinnerViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }



class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {

// infla layout dentro do container pai

}

}
DELEGATE ADAPTERS | NEWS
NewsDelegateAdapter.kt
class NewsAdapterDelegate : ViewTypeDelegateAdapter {

override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {

holder as NewsViewHolder

holder.bind(item as RedditNewsItem)

}



class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {



fun bind(item : RedditNewsItem) = with(itemView) {

img_thumbnail.loadImgUrl(item.thumbnail)

description.text = item.title

author.text = item.author

comments.text = "${item.commentsNumber} comments"

}

}

}
DELEGATE ADAPTERS | NEWS
NewsDelegateAdapter.kt
class NewsAdapterDelegate : ViewTypeDelegateAdapter {

override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {

holder as NewsViewHolder

holder.bind(item as RedditNewsItem)

}



class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {



fun bind(item : RedditNewsItem) = with(itemView) {

img_thumbnail.loadImgUrl(item.thumbnail)

description.text = item.title

author.text = item.author

comments.text = "${item.commentsNumber} comments"

}

}

}
DELEGATE ADAPTERS | NEWS
NewsDelegateAdapter.kt
class NewsAdapterDelegate : ViewTypeDelegateAdapter {

override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {

holder as NewsViewHolder

holder.bind(item as RedditNewsItem)

}



class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {



fun bind(item : RedditNewsItem) = with(itemView) {

img_thumbnail.loadImgUrl(item.thumbnail)

description.text = item.title

author.text = item.author

comments.text = "${item.commentsNumber} comments"

}

}

}
Smart cast
DELEGATE ADAPTERS | NEWS
NewsDelegateAdapter.kt
class NewsAdapterDelegate : ViewTypeDelegateAdapter {

override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)



override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {

holder as NewsViewHolder

holder.bind(item as RedditNewsItem)

}



class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder

(parent.inflate(R.layout.news_item_loading)) {



fun bind(item : RedditNewsItem) = with(itemView) {

img_thumbnail.loadImgUrl(item.thumbnail)

description.text = item.title

author.text = item.author

comments.text = "${item.commentsNumber} comments"

}

}

}
DELEGATE ADAPTERS | NEWS
- Carregando imagem no bind
- Extension functions


fun ImageView.loadImgUrl(imageUrl: String?) {

if (imageUrl.isNullOrEmpty()) {

Picasso.with(context).load(R.mipmap.ic_launcher).into(this)

} else {

Picasso.with(context).load(imageUrl).into(this)

}

}
ADICIONANDO ALGUNS DADOS MOCK
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

override fun onActivityCreated(savedInstanceState: Bundle?) {

// …

val newsAdapter = NewsAdapter()

newsList.adapter = newsAdapter



if (savedInstanceState == null) {

newsAdapter.addNews(mockData())

}

}



private fun mockData() : List<RedditNewsItem> {

val news = mutableListOf<RedditNewsItem>()



for (i in 1..10) {

news.add(RedditNewsItem(

"Author $i",

"Title $i",

"http://lorempixel.com/200/200/technics/$i", // thumbnail

i // number of comments

))

}



return news

}

}
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

override fun onActivityCreated(savedInstanceState: Bundle?) {

// …

val newsAdapter = NewsAdapter()

newsList.adapter = newsAdapter



if (savedInstanceState == null) {

newsAdapter.addNews(mockData())

}

}

}
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

override fun onActivityCreated(savedInstanceState: Bundle?) {

// …

val newsAdapter = NewsAdapter()

newsList.adapter = newsAdapter



if (savedInstanceState == null) {

newsAdapter.addNews(mockData())

}

}

}
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

override fun onActivityCreated(savedInstanceState: Bundle?) {

// …

val newsAdapter = NewsAdapter()

newsList.adapter = newsAdapter



if (savedInstanceState == null) {

newsAdapter.addNews(mockData())

}

}



private fun mockData() : List<RedditNewsItem> {

val news = mutableListOf<RedditNewsItem>()



for (i in 1..10) {

news.add(RedditNewsItem(

"Author $i",

"Title $i",

"http://lorempixel.com/200/200/technics/$i", // thumbnail

i // number of comments

))

}



return news

}

}
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

private fun mockData() : List<RedditNewsItem> {

val news = mutableListOf<RedditNewsItem>()



for (i in 1..10) {

news.add(RedditNewsItem(

"Author $i",

"Title $i",

"http://lorempixel.com/200/200/technics/$i", // thumbnail

i // number of comments

))

}

return news

}

}
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

private fun mockData() : List<RedditNewsItem> {

val news = mutableListOf<RedditNewsItem>()



for (i in 1..10) {

news.add(RedditNewsItem(

"Author $i",

"Title $i",

"http://lorempixel.com/200/200/technics/$i", // thumbnail

i // number of comments

))

}

return news

}

}
ADICIONANDO ALGUNS DADOS MOCK
class NewsFragment : Fragment() {

// …

private fun mockData() : List<RedditNewsItem> {

val news = mutableListOf<RedditNewsItem>()



for (i in 1..10) {

news.add(RedditNewsItem(

"Author $i",

"Title $i",

"http://lorempixel.com/200/200/technics/$i", // thumbnail

i // number of comments

))

}

return news

}

}
ADICIONANDO ALGUNS DADOS MOCK
OUTRAS DICAS
OUTRAS DICAS | CLICK LISTENERS
myButton.setOnClickListener { navigateToDetail() }
OUTRAS DICAS | OPTION MENU
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.action_settings -> consume { navigateToSettings() }
R.id.nav_camera -> drawer.consume { navigateToCamera() }
R.id.nav_gallery -> drawer.consume { loadGallery() }
R.id.nav_slideshow -> drawer.consume { loadSlideshow() }
else -> super.onOptionsItemSelected(item)
}
OUTRAS DICAS | OPTION MENU
inline fun consume(f: () -> Unit): Boolean {
f()
return true
}
inline fun DrawerLayout.consume(f: () -> Unit): Boolean {
f()
closeDrawers()
return true
}
OUTRAS DICAS | LAMBDAS
view.postDelayed({ doWhatever() }, 200)





Thread().run {
// Running in a thread
}
OUTRAS DICAS | COLLECTIONS
return parsedContacts.filter { it.name != null && it.image != null }
.sortedBy { it.name }
.map { Contact(it.id, it.name!!, it.image!!) }
OUTRAS DICAS | ANKO
- DSL
- Useful Helpers
OUTRAS DICAS | ANKO - DSL
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
verticalLayout {
padding = dip(30)
editText {
hint = "Name"
textSize = 24f
}
editText {
hint = "Password"
textSize = 24f
}
button("Login") {
textSize = 26f // usando tamanho em SP
}
}
}
OUTRAS DICAS | ANKO
- DSL
- Useful Helpers
OUTRAS DICAS | ANKO - Useful Helpers
- Fazer ligação makeCall(numeroTelefone)
- Abrir browser browse(url)

- Compartilha texto share(text, [assunto])

- Enviar email email(email, [assunto], [texto])

- Abrir activity startActivity<SomeOtherActivity>("id" to 5)
OUTRAS DICAS | ANKO - Useful Helpers
async() {
// Faz algo em background
uiThread {
// Volta para main thread
}
}
LINKS
Kotlin Lang:
- https://kotlinlang.org/
Kotlin Roadmap
- http://go.arctouch.com/kotlin-roadmap
https://github.com/arctouch-luizsantana/tdc-kotlin
OBRIGADO.
Big Brains Wanted
Join our team! Go to arctouch.com/brjobs
Visit our booth to win an Apple Watch.
Ad

More Related Content

What's hot (20)

Coffeescript: No really, it's just Javascript
Coffeescript: No really, it's just JavascriptCoffeescript: No really, it's just Javascript
Coffeescript: No really, it's just Javascript
Brian Mann
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Raimonds Simanovskis
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.
boyney123
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
Raimonds Simanovskis
 
Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012
Jo Cranford
 
Finding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iteratorsFinding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iterators
Luciano Mammino
 
LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기
Wanbok Choi
 
Connecting your phone and home with firebase and android things - James Cogga...
Connecting your phone and home with firebase and android things - James Cogga...Connecting your phone and home with firebase and android things - James Cogga...
Connecting your phone and home with firebase and android things - James Cogga...
DroidConTLV
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
Manoj Kumar
 
Modern JS with ES6
Modern JS with ES6Modern JS with ES6
Modern JS with ES6
Kevin Langley Jr.
 
Chloe and the Realtime Web
Chloe and the Realtime WebChloe and the Realtime Web
Chloe and the Realtime Web
Trotter Cashion
 
Kotlin
KotlinKotlin
Kotlin
Rory Preddy
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Codemotion
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritageWhat's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
Finding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iteratorsFinding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iterators
Luciano Mammino
 
JavaScript Web Development
JavaScript Web DevelopmentJavaScript Web Development
JavaScript Web Development
vito jeng
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6
Solution4Future
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
Ingvar Stepanyan
 
No excuses, switch to kotlin
No excuses, switch to kotlinNo excuses, switch to kotlin
No excuses, switch to kotlin
Thijs Suijten
 
Coffeescript: No really, it's just Javascript
Coffeescript: No really, it's just JavascriptCoffeescript: No really, it's just Javascript
Coffeescript: No really, it's just Javascript
Brian Mann
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Raimonds Simanovskis
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.
boyney123
 
Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012Less ismorewithcoffeescript webdirectionsfeb2012
Less ismorewithcoffeescript webdirectionsfeb2012
Jo Cranford
 
Finding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iteratorsFinding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iterators
Luciano Mammino
 
LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기LetSwift RxSwift 시작하기
LetSwift RxSwift 시작하기
Wanbok Choi
 
Connecting your phone and home with firebase and android things - James Cogga...
Connecting your phone and home with firebase and android things - James Cogga...Connecting your phone and home with firebase and android things - James Cogga...
Connecting your phone and home with firebase and android things - James Cogga...
DroidConTLV
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
Manoj Kumar
 
Chloe and the Realtime Web
Chloe and the Realtime WebChloe and the Realtime Web
Chloe and the Realtime Web
Trotter Cashion
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Codemotion
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritageWhat's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 
"Kotlin и rx в android" Дмитрий Воронин (Avito)
"Kotlin и rx в android" Дмитрий Воронин  (Avito)"Kotlin и rx в android" Дмитрий Воронин  (Avito)
"Kotlin и rx в android" Дмитрий Воронин (Avito)
AvitoTech
 
Finding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iteratorsFinding a lost song with Node.js and async iterators
Finding a lost song with Node.js and async iterators
Luciano Mammino
 
JavaScript Web Development
JavaScript Web DevelopmentJavaScript Web Development
JavaScript Web Development
vito jeng
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6
Solution4Future
 
AST - the only true tool for building JavaScript
AST - the only true tool for building JavaScriptAST - the only true tool for building JavaScript
AST - the only true tool for building JavaScript
Ingvar Stepanyan
 
No excuses, switch to kotlin
No excuses, switch to kotlinNo excuses, switch to kotlin
No excuses, switch to kotlin
Thijs Suijten
 

Similar to Criando app Android utilizando Kotlin (20)

Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
Aleksandar Prokopec
 
An Introduction to Scala (2014)
An Introduction to Scala (2014)An Introduction to Scala (2014)
An Introduction to Scala (2014)
William Narmontas
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
Lorenzo Dematté
 
A bit about Scala
A bit about ScalaA bit about Scala
A bit about Scala
Vladimir Parfinenko
 
Intro toswift1
Intro toswift1Intro toswift1
Intro toswift1
Jordan Morgan
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
Arnaud Giuliani
 
Let's fly to the Kotlin Island. Just an introduction to Kotlin
Let's fly to the Kotlin Island. Just an introduction to KotlinLet's fly to the Kotlin Island. Just an introduction to Kotlin
Let's fly to the Kotlin Island. Just an introduction to Kotlin
Aliaksei Zhynhiarouski
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
Bartosz Kosarzycki
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
STX Next
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
intelliyole
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar Prokopec
Loïc Descotte
 
Scala introduction
Scala introductionScala introduction
Scala introduction
Alf Kristian Støyle
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
Arnaud Giuliani
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kirill Rozov
 
Hello kotlin | An Event by DSC Unideb
Hello kotlin | An Event by DSC UnidebHello kotlin | An Event by DSC Unideb
Hello kotlin | An Event by DSC Unideb
Muhammad Raza
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
Franco Lombardo
 
An Introduction to Scala (2014)
An Introduction to Scala (2014)An Introduction to Scala (2014)
An Introduction to Scala (2014)
William Narmontas
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
Arnaud Giuliani
 
Let's fly to the Kotlin Island. Just an introduction to Kotlin
Let's fly to the Kotlin Island. Just an introduction to KotlinLet's fly to the Kotlin Island. Just an introduction to Kotlin
Let's fly to the Kotlin Island. Just an introduction to Kotlin
Aliaksei Zhynhiarouski
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
Bartosz Kosarzycki
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
STX Next
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
intelliyole
 
Scala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar ProkopecScala presentation by Aleksandar Prokopec
Scala presentation by Aleksandar Prokopec
Loïc Descotte
 
Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017Develop your next app with kotlin @ AndroidMakersFr 2017
Develop your next app with kotlin @ AndroidMakersFr 2017
Arnaud Giuliani
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kirill Rozov
 
Hello kotlin | An Event by DSC Unideb
Hello kotlin | An Event by DSC UnidebHello kotlin | An Event by DSC Unideb
Hello kotlin | An Event by DSC Unideb
Muhammad Raza
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
Hiroshi Ono
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
Franco Lombardo
 
Ad

Recently uploaded (20)

Vaibhav Gupta BAML: AI work flows without Hallucinations
Vaibhav Gupta BAML: AI work flows without HallucinationsVaibhav Gupta BAML: AI work flows without Hallucinations
Vaibhav Gupta BAML: AI work flows without Hallucinations
john409870
 
Play It Safe: Manage Security Risks - Google Certificate
Play It Safe: Manage Security Risks - Google CertificatePlay It Safe: Manage Security Risks - Google Certificate
Play It Safe: Manage Security Risks - Google Certificate
VICTOR MAESTRE RAMIREZ
 
Vibe Coding_ Develop a web application using AI (1).pdf
Vibe Coding_ Develop a web application using AI (1).pdfVibe Coding_ Develop a web application using AI (1).pdf
Vibe Coding_ Develop a web application using AI (1).pdf
Baiju Muthukadan
 
Connect and Protect: Networks and Network Security
Connect and Protect: Networks and Network SecurityConnect and Protect: Networks and Network Security
Connect and Protect: Networks and Network Security
VICTOR MAESTRE RAMIREZ
 
Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...
Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...
Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...
Raffi Khatchadourian
 
AI Agents at Work: UiPath, Maestro & the Future of Documents
AI Agents at Work: UiPath, Maestro & the Future of DocumentsAI Agents at Work: UiPath, Maestro & the Future of Documents
AI Agents at Work: UiPath, Maestro & the Future of Documents
UiPathCommunity
 
MINDCTI revenue release Quarter 1 2025 PR
MINDCTI revenue release Quarter 1 2025 PRMINDCTI revenue release Quarter 1 2025 PR
MINDCTI revenue release Quarter 1 2025 PR
MIND CTI
 
Transcript: Canadian book publishing: Insights from the latest salary survey ...
Transcript: Canadian book publishing: Insights from the latest salary survey ...Transcript: Canadian book publishing: Insights from the latest salary survey ...
Transcript: Canadian book publishing: Insights from the latest salary survey ...
BookNet Canada
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
TrsLabs - Leverage the Power of UPI Payments
TrsLabs - Leverage the Power of UPI PaymentsTrsLabs - Leverage the Power of UPI Payments
TrsLabs - Leverage the Power of UPI Payments
Trs Labs
 
UiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer OpportunitiesUiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer Opportunities
DianaGray10
 
Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...
Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...
Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...
Raffi Khatchadourian
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
GyrusAI - Broadcasting & Streaming Applications Driven by AI and ML
GyrusAI - Broadcasting & Streaming Applications Driven by AI and MLGyrusAI - Broadcasting & Streaming Applications Driven by AI and ML
GyrusAI - Broadcasting & Streaming Applications Driven by AI and ML
Gyrus AI
 
TrsLabs Consultants - DeFi, WEb3, Token Listing
TrsLabs Consultants - DeFi, WEb3, Token ListingTrsLabs Consultants - DeFi, WEb3, Token Listing
TrsLabs Consultants - DeFi, WEb3, Token Listing
Trs Labs
 
AI You Can Trust: The Critical Role of Governance and Quality.pdf
AI You Can Trust: The Critical Role of Governance and Quality.pdfAI You Can Trust: The Critical Role of Governance and Quality.pdf
AI You Can Trust: The Critical Role of Governance and Quality.pdf
Precisely
 
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à GenèveUiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPathCommunity
 
The Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI IntegrationThe Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI Integration
Re-solution Data Ltd
 
Webinar - Top 5 Backup Mistakes MSPs and Businesses Make .pptx
Webinar - Top 5 Backup Mistakes MSPs and Businesses Make   .pptxWebinar - Top 5 Backup Mistakes MSPs and Businesses Make   .pptx
Webinar - Top 5 Backup Mistakes MSPs and Businesses Make .pptx
MSP360
 
Vaibhav Gupta BAML: AI work flows without Hallucinations
Vaibhav Gupta BAML: AI work flows without HallucinationsVaibhav Gupta BAML: AI work flows without Hallucinations
Vaibhav Gupta BAML: AI work flows without Hallucinations
john409870
 
Play It Safe: Manage Security Risks - Google Certificate
Play It Safe: Manage Security Risks - Google CertificatePlay It Safe: Manage Security Risks - Google Certificate
Play It Safe: Manage Security Risks - Google Certificate
VICTOR MAESTRE RAMIREZ
 
Vibe Coding_ Develop a web application using AI (1).pdf
Vibe Coding_ Develop a web application using AI (1).pdfVibe Coding_ Develop a web application using AI (1).pdf
Vibe Coding_ Develop a web application using AI (1).pdf
Baiju Muthukadan
 
Connect and Protect: Networks and Network Security
Connect and Protect: Networks and Network SecurityConnect and Protect: Networks and Network Security
Connect and Protect: Networks and Network Security
VICTOR MAESTRE RAMIREZ
 
Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...
Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...
Challenges in Migrating Imperative Deep Learning Programs to Graph Execution:...
Raffi Khatchadourian
 
AI Agents at Work: UiPath, Maestro & the Future of Documents
AI Agents at Work: UiPath, Maestro & the Future of DocumentsAI Agents at Work: UiPath, Maestro & the Future of Documents
AI Agents at Work: UiPath, Maestro & the Future of Documents
UiPathCommunity
 
MINDCTI revenue release Quarter 1 2025 PR
MINDCTI revenue release Quarter 1 2025 PRMINDCTI revenue release Quarter 1 2025 PR
MINDCTI revenue release Quarter 1 2025 PR
MIND CTI
 
Transcript: Canadian book publishing: Insights from the latest salary survey ...
Transcript: Canadian book publishing: Insights from the latest salary survey ...Transcript: Canadian book publishing: Insights from the latest salary survey ...
Transcript: Canadian book publishing: Insights from the latest salary survey ...
BookNet Canada
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
TrsLabs - Leverage the Power of UPI Payments
TrsLabs - Leverage the Power of UPI PaymentsTrsLabs - Leverage the Power of UPI Payments
TrsLabs - Leverage the Power of UPI Payments
Trs Labs
 
UiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer OpportunitiesUiPath Agentic Automation: Community Developer Opportunities
UiPath Agentic Automation: Community Developer Opportunities
DianaGray10
 
Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...
Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...
Hybridize Functions: A Tool for Automatically Refactoring Imperative Deep Lea...
Raffi Khatchadourian
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
Transcript: #StandardsGoals for 2025: Standards & certification roundup - Tec...
BookNet Canada
 
GyrusAI - Broadcasting & Streaming Applications Driven by AI and ML
GyrusAI - Broadcasting & Streaming Applications Driven by AI and MLGyrusAI - Broadcasting & Streaming Applications Driven by AI and ML
GyrusAI - Broadcasting & Streaming Applications Driven by AI and ML
Gyrus AI
 
TrsLabs Consultants - DeFi, WEb3, Token Listing
TrsLabs Consultants - DeFi, WEb3, Token ListingTrsLabs Consultants - DeFi, WEb3, Token Listing
TrsLabs Consultants - DeFi, WEb3, Token Listing
Trs Labs
 
AI You Can Trust: The Critical Role of Governance and Quality.pdf
AI You Can Trust: The Critical Role of Governance and Quality.pdfAI You Can Trust: The Critical Role of Governance and Quality.pdf
AI You Can Trust: The Critical Role of Governance and Quality.pdf
Precisely
 
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à GenèveUiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPath Automation Suite – Cas d'usage d'une NGO internationale basée à Genève
UiPathCommunity
 
The Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI IntegrationThe Future of Cisco Cloud Security: Innovations and AI Integration
The Future of Cisco Cloud Security: Innovations and AI Integration
Re-solution Data Ltd
 
Webinar - Top 5 Backup Mistakes MSPs and Businesses Make .pptx
Webinar - Top 5 Backup Mistakes MSPs and Businesses Make   .pptxWebinar - Top 5 Backup Mistakes MSPs and Businesses Make   .pptx
Webinar - Top 5 Backup Mistakes MSPs and Businesses Make .pptx
MSP360
 
Ad

Criando app Android utilizando Kotlin

  • 1. CRIANDO APP ANDROID UTILIZANDO KOTLIN Luiz Santana / André Cardoso
  • 2. QUAL É O PROBLEMA?
  • 3. - Java 8 no Android N - Streams - API level 23 ou RxJava - Lambdas, referências à métodos, non-capturing - API level 23 ou Retrolambda - Try with resources - API level 19 ou Retrolambda - Métodos default em interfaces - API level 23 Android Moderninho
  • 4. - Não dá pra adicionar métodos à tipos existentes - *Util em todo lugar - Nulls - NPEs em todo lugar - Java é verboso - APIs do Android são complexas - Herança e nulls em todo lugar Limitações do Java no Android
  • 6. - JetBrains - JVM - Concisa, Segura, Versátil, Interoperável
  • 7. package hello
 
 fun main(args: Array<String>) {
 println("Hello TDC!")
 }
  • 8. fun welcome(name: String, event: String): String {
 return "Hello ${name}, welcome to ${event}!"
 } Functions
  • 9. fun welcome(name: String, event: String) = "Hello ${name}, welcome to ${event}!" Functions
  • 10. fun main(args: Array<String>) {
 val greeting = welcome("André", "TDC")
 println(greeting)
 } Functions
  • 11. fun main(args: Array<String>) {
 val greeting = welcome("André", "TDC")
 println(greeting)
 
 greeting = welcome("Luiz", "TDC")
 println(greeting)
 } Variáveis
  • 12. fun main(args: Array<String>) {
 var greeting = welcome("André", "TDC")
 println(greeting)
 
 greeting = welcome("Luiz", "TDC")
 println(greeting)
 } Variáveis
  • 13. fun welcome(name: String, event: String = "TDC")
 = "Hello ${name}, welcome to ${event}!"
 
 Parâmetros Default
  • 14. fun main(args: Array<String>) {
 val greeting = welcome("André")
 println(greeting)
 } Parâmetros Default
  • 15. fun main(args: Array<String>) {
 val greeting = welcome(name = "Luiz", event = "I/O")
 println(greeting)
 } Parâmetros Default
  • 16. fun welcome(name: String = "Developer", event: String = "TDC")
 = "Hello ${name}, welcome to ${event}!"
 
 Parâmetros Default
  • 17. fun main(args: Array<String>) {
 val greeting = welcome(event = “Android Meetup")
 println(greeting)
 } Parâmetros Default
  • 18. fun main(args: Array<String>) {
 val greeting = welcome()
 println(greeting)
 } Parâmetros Default
  • 19. val lyrics = """
 |Jamais a natureza
 |Reuniu tanta beleza
 |Jamais algum poeta
 |Teve tanto pra cantar!
 “"".trimMargin() println(lyrics)
 
 val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"
 var datePattern = """d{2} ${month} d{4}"""
 
 val today = "13 MAY 2016".matches(Regex(datePattern))
 println(today) String Templates
  • 20. val famousPeople = arrayListOf<String>("Einstein", "Newton", "MC Biel")
 
 val forSure = famousPeople is java.util.ArrayList
 println(forSure) Collections
  • 21. val famousPeople = arrayListOf<String>("Einstein", "Newton", "MC Bin Laden")
 
 val pairs = famousPeople.map { Pair(it, it == "MC Bin Laden") }
 
 pairs.forEach {
 val (name, singer) = it
 val verb = if (singer) "is" else "is not"
 println("${name} ${verb} a singer")
 } Lambdas
  • 22. val pairs = famousPeople.map { Pair(it, it == "MC Bin Laden") } Equality
  • 23. pairs.forEach {
 val (name, singer) = it
 val verb = if (singer) "is" else "is not"
 println("${name} ${verb} a singer")
 } Destructors e if expressions
  • 24. fun String.isSinger() = this == "MC Bin Laden" Extension Functions
  • 25. val famousPeople = arrayListOf<String>("Einstein", "Newton", "MC Bin Laden")
 
 famousPeople.forEach {
 val verb = if (it.isSinger()) "is" else "is not"
 println("${it} ${verb} a singer")
 } Extension Functions
  • 26. fun SQLiteDatabase.transaction(code: SQLiteDatabase.() -> Unit) {
 try {
 beginTransaction()
 code()
 setTransactionSuccessful()
 } catch (e: TransactionAbortException) {
 // Do nothing, just stop the transaction
 } finally {
 endTransaction()
 }
 }
 
 fun SQLiteDatabase.delete(tableName: String, whereClause: String = "", vararg args: Pair<String, Any>): Int { …
 } Extension Functions
  • 27. db.transaction {
 db.delete("people", "is_singer = ?", "is_singer" to true)
 } Extension Functions
  • 28. fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {
 val email = client?.personalInfo?.email ?: "[email protected]"
 if (message != null) {
 mailer.sendMessage(email, message)
 }
 } Tipos Null
  • 29. fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {
 val email = client?.personalInfo?.email ?: "[email protected]"
 if (message != null) {
 mailer.sendMessage(email, message)
 }
 } Null Safe Calls
  • 30. fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {
 val email = client?.personalInfo?.email ?: "[email protected]"
 if (message != null) {
 mailer.sendMessage(email, message)
 }
 } Elvis
  • 31. fun sendEmailToClient(client: Client?, message: String?, mailer: Mailer) {
 val email = client?.personalInfo?.email ?: "[email protected]"
 if (message != null) {
 mailer.sendMessage(email, message)
 }
 } Smart Cast
  • 32. fun eval(expr: Expr): Int =
 when (expr) {
 is Num -> expr.value
 is Sum -> eval(expr.left) + eval(expr.right)
 else -> throw IllegalArgumentException("Unknown expression")
 }
 
 interface Expr
 class Num(val value: Int) : Expr
 class Sum(val left: Expr, val right: Expr) : Expr Smart Cast
  • 33. class Person constructor(name: String) {
 }
 
 class Singer(name: String, isSinger: Boolean) : Person(name) {
 } Classes
  • 34. open class Person constructor(name: String) {
 }
 
 class Singer(name: String, isSinger: Boolean) : Person(name) {
 } Classes
  • 35. open class Person constructor(name: String) {
 open fun walk() {
 println("walking as a normal person")
 }
 }
 
 class Singer(name: String, isSinger: Boolean) : Person(name) {
 override fun walk() {
 println("walking with some style")
 }
 } Classes
  • 36. interface Funk {
 var views: Long
 
 fun funk() {
 views++
 println("ta tranquilo ta favorável")
 }
 } class Singer(name: String, isSinger: Boolean, override var views: Long) : Funk Interfaces
  • 37. fun main(args: Array<String>) {
 val mc = Singer("MC Bin Laden", true)
 mc.funk()
 mc.walk()
 } Interfaces
  • 38. interface Moveable {
 fun move() { print("move") }
 }
 
 interface Walkable {
 fun move() { walk() }
 fun walk() { print("walk") }
 }
 
 class Human : Moveable, Walkable {
 override fun move() {
 super<Walkable>.move()
 }
 } Interfaces - Resolução de conflitos
  • 39. data class Singer(val name: String, val isSinger: Boolean, override var views: Long) : Funk fun main(args: Array<String>) {
 val mc = Singer("MC Bin Laden", isSinger = true, views = 10000000)
 println(mc.toString())
 println(mc.hashCode())
 println(mc.copy(name = "Catra"))
 } Singer(name=MC Bin Laden, isSinger=true, views=10000001) -117390027 Singer(name=Catra, isSinger=true, views=10000001) Data class
  • 40. class Panelist {
 val presentation : String by lazy {
 "Kotlin!!!!"
 }
 
 var numberOfQuestions : Int by Delegates.observable(0) {
 prop, old, new ->
 println("It was ${old} not it is ${new}")
 }
 } Delegated properties
  • 43. CRIANDO O APP | OBJETIVO - Criar um app em Kotlin - Consumir dados MOCK, simulando “News feed” do Reddit
  • 44. CRIANDO O APP | PRIMEIRO PASSO - Criar projeto com Activity básica
  • 45. - Instalando Plugin: - Preferences - Plugins - Buscar por “Kotlin” CRIANDO O APP | PLUGIN
  • 46. CRIANDO O APP | CONFIGURANDO - Abrir painel de ações - ctrl + shift + A - cmd + shift + A
  • 48. apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 
 android {
 …
 sourceSets {
 main.java.srcDirs += 'src/main/kotlin'
 }
 }
 
 dependencies { …
 compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
 }
 buildscript {
 ext.kotlin_version = '1.0.1-2'
 repositories {
 mavenCentral()
 }
 dependencies {
 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
 }
 }
 build.gradle
  • 50. public class MainActivity extends AppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
 setSupportActionBar(toolbar);
 
 FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
 fab.setOnClickListener(new OnClickListener(…) { … });
 }
 
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
 getMenuInflater().inflate(R.menu.menu_main, menu);
 return true;
 } … } MainActivity.java
  • 51. Java -> Kotlin | CONVERTENDO - Convertendo código - Abrir painel ação - Buscar por “Convert Java…”
  • 52. E A MÁGICA ACONTECE…
  • 53. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener({ view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 }
 
 override fun onCreateOptionsMenu(menu: Menu): Boolean {
 menuInflater.inflate(R.menu.menu_main, menu)
 return true
 } …
 } MainActivity.kt
  • 54. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main) …
 MainActivity.kt
  • 55. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main) …
 MainActivity.kt
  • 56. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main) …
 MainActivity.kt
  • 57. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main) …
 MainActivity.kt
  • 58. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main) …
 MainActivity.kt
  • 59. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener({ view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 }
 
 override fun onCreateOptionsMenu(menu: Menu): Boolean {
 menuInflater.inflate(R.menu.menu_main, menu)
 return true
 } …
 } MainActivity.kt
  • 60. class MainActivity : AppCompatActivity() {
 …
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener(
 { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 } …
 } MainActivity.kt
  • 61. class MainActivity : AppCompatActivity() {
 …
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener(
 { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 } …
 } MainActivity.kt
  • 62. class MainActivity : AppCompatActivity() {
 …
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener(
 { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 } …
 } MainActivity.kt
  • 63. class MainActivity : AppCompatActivity() {
 …
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener(
 { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 } …
 } MainActivity.kt
  • 64. class MainActivity : AppCompatActivity() {
 …
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener(
 { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 } …
 } MainActivity.kt
  • 65. class MainActivity : AppCompatActivity() {
 
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 val toolbar = findViewById(R.id.toolbar) as Toolbar?
 setSupportActionBar(toolbar)
 
 val fab = findViewById(R.id.fab) as FloatingActionButton?
 fab?.setOnClickListener({ view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() })
 }
 
 override fun onCreateOptionsMenu(menu: Menu): Boolean {
 menuInflater.inflate(R.menu.menu_main, menu)
 return true
 } …
 } MainActivity.kt
  • 66. Criando o App | APP RODANDO
  • 68. FRAGMENT | MUDANÇAS - Adicionado Fragment Management - Removido Float Button - Removido Option Menu
  • 69. FRAGMENT | LAYOUT - Criando um layout Simples <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android=“….”
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <android.support.v7.widget.RecyclerView
 android:id="@+id/news_list"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content">
 </android.support.v7.widget.RecyclerView> 
 </RelativeLayout>
  • 70. FRAGMENT | KOTLIN CODE class NewsFragment : Fragment() {
 private var newsList: RecyclerView? = null
 
 override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, 
 savedInstanceState: Bundle?): View? {
 val view = inflater?.inflate(R.layout.fragment_news, container, false)
 newsList = view?.findViewById(R.id.news_list) as RecyclerView?
 newsList?.setHasFixedSize(true)
 newsList?.layoutManager = LinearLayoutManager(context)
 
 return view
 }
 }
  • 71. FRAGMENT | KOTLIN CODE class NewsFragment : Fragment() {
 private var newsList: RecyclerView? = null
 
 override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, 
 savedInstanceState: Bundle?): View? {
 val view = inflater?.inflate(R.layout.fragment_news, container, false)
 newsList = view?.findViewById(R.id.news_list) as RecyclerView?
 newsList?.setHasFixedSize(true)
 newsList?.layoutManager = LinearLayoutManager(context)
 
 return view
 }
 } Como melhorar
 o código?
  • 73. EXTENSION FUNCTIONS | INFLATE Como fazer o código abaixo ficar mais intuitivo? …
 val view = inflater?.inflate(R.layout.fragment_news, container, false) 
 … …
 val view = container?.inflate(R.layout.fragment_news) 
 …
  • 74. EXTENSION FUNCTIONS | INFLATE Como implementar? // ExtensionsKt.kt
 
 fun ViewGroup.inflate(layoutId : Int) : View {
 return LayoutInflater.from(context).inflate(layoutId, this, false)
 }
  • 75. EXTENSION FUNCTIONS | INFLATE Reuso do código // Java
 ExtensionsKt.inflate(container, R.layout.news_fragment);
 // Kotlin
 container?.inflate(R.layout.fragment_news) @file:JvmName("ExtensionsUtils")
 package com.arctouch.kotlin.commons.extensions
 …
 // Usar assim em Java: ExtensionsUtils.inflate(container, R.layout.news_fragment);
  • 76. EXTENSION FUNCTIONS | INFLATE Parâmetros com valor padrão fun ViewGroup.inflate(layoutId : Int, attachToRoot : Boolean = false) : View {
 return LayoutInflater.from(context).inflate(layoutId, this, attachToRoot)
 }
 
 // usar assim val view = container?.inflate(R.layout.fragment_news) // default: false 
 // ou assim
 val view = container?.inflate(R.layout.fragment_news, true)
  • 78. ANDROID EXTENSIONS | ADICIONANDO apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-android-extensions' Adicionar no build.gradle
  • 79. ANDROID EXTENSIONS | FUNCIONALIDADE - Voltando ao Layout do Fragment… <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android=“….”
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 
 <android.support.v7.widget.RecyclerView
 android:id="@+id/news_list"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content">
 </android.support.v7.widget.RecyclerView> 
 </RelativeLayout>
  • 80. ANDROID EXTENSIONS | FUNCIONALIDADE // importar no código // import kotlinx.android.synthetic.<MODULO>.<VIEW>.* import kotlinx.android.synthetic.main.fragment_news.* // código antigo
 newsList = view?.findViewById(R.id.news_list) as RecyclerView?
 newsList?.setHasFixedSize(true)
 newsList?.layoutManager = LinearLayoutManager(context)
 
 // código novo
 news_list.setHasFixedSize(true)
 news_list.layoutManager = LinearLayoutManager(context)
  • 82. LAZY PROPERTIES | INTRO private val newsList by lazy {
 news_list
 } override fun onActivityCreated(savedInstanceState: Bundle?) {
 super.onActivityCreated(savedInstanceState)
 
 newsList.setHasFixedSize(true) // Executado de maneira Lazy
 newsList.layoutManager = LinearLayoutManager(context)
 }
 }
  • 84. CRIANDO ADAPTER | INICIO - Usaremos padrão DelegateAdapter - A ideia é ter diferentes tipos de view num mesmo adapter - Neste caso teremos algo parecido com:
  • 85. CRIANDO ADAPTER | ESTRUTURA - Cada ViewItem possui um ViewType enum class ViewType {
 LOADING,
 NEWS
 } interface ViewDelegate {
 fun getType() : ViewType
 }
  • 86. CRIANDO ADAPTER | O ADAPTER - Nosso NewsAdapter 
 class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 
 private val items: ArrayList<ViewItem> = ArrayList() // outros métodos…
 }
  • 87. CRIANDO ADAPTER | O ADAPTER - Nosso NewsAdapter 
 class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 
 private val items: ArrayList<ViewItem> = ArrayList()
 private val delegateAdapters: HashMap<ViewType,
 ViewTypeDelegateAdapter> = HashMap()
 // outros métodos…
 }
  • 88. CRIANDO ADAPTER | O ADAPTER - Nosso NewsAdapter 
 class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 
 private val items: ArrayList<ViewItem> = ArrayList()
 private val delegateAdapters: HashMap<ViewType, ViewTypeDelegateAdapter> = HashMap()
 
 init {
 delegateAdapters.put(ViewType.LOADING, LoadingDelegateAdapter())
 } // outros métodos…
 }
  • 89. CRIANDO ADAPTER | O ADAPTER - Nosso NewsAdapter 
 class NewsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 
 private val items: ArrayList<ViewItem> = ArrayList()
 private val delegateAdapters: HashMap<ViewType, ViewTypeDelegateAdapter> = HashMap()
 private val loadingItem = object : ViewItem {
 override fun getType() : ViewType = ViewType.LOADING
 }
 
 init {
 delegateAdapters.put(ViewType.LOADING, LoadingDelegateAdapter())
 items.add(loadingItem)
 } // outros métodos…
 }
  • 91. DATA CLASSES | MODEL - Clássico Java model public class RedditNewsItem {
 private String author;
 private String title;
 
 public RedditNewsItem(String author, String title) {
 this.author = author;
 this.title = title;
 }
 
 public String getAuthor() {
 return author;
 }
 
 public void setAuthor(String author) {
 this.author = author;
 }
 
 public String getTitle() {
 return title;
 }
 
 public void setTitle(String title) {
 this.title = title;
 }
 }
  • 92. DATA CLASSES | MODEL - Kotlin data class data class RedditNewsItem(var author: String, var title: String) 
 Java Model + 
 equals/hashCode 
 toString
 copy

  • 94. DELEGATE ADAPTERS | ESTRUTURA - Criando estrutura inicial interface ViewTypeDelegateAdapter {
 fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
 fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType)
 }
  • 95. DELEGATE ADAPTERS | LOADING LoadingDelegateAdapter.kt class LoadingDelegateAdapter : ViewTypeDelegateAdapter {
 
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
 = SpinnerViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }
 
 class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 // infla layout em cima do pai
 }
 }
  • 96. DELEGATE ADAPTERS | LOADING LoadingDelegateAdapter.kt class LoadingDelegateAdapter : ViewTypeDelegateAdapter {
 
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
 = SpinnerViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }
 
 class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 // infla layout em cima do pai
 }
 }
  • 97. DELEGATE ADAPTERS | LOADING LoadingDelegateAdapter.kt class LoadingDelegateAdapter : ViewTypeDelegateAdapter {
 
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
 = SpinnerViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }
 
 class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 // infla layout em cima do pai
 }
 }
  • 98. DELEGATE ADAPTERS | LOADING LoadingDelegateAdapter.kt class LoadingDelegateAdapter : ViewTypeDelegateAdapter {
 
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
 = SpinnerViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }
 
 class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 // infla layout em cima do pai
 }
 }
  • 99. DELEGATE ADAPTERS | LOADING LoadingDelegateAdapter.kt class LoadingDelegateAdapter : ViewTypeDelegateAdapter {
 
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
 = SpinnerViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewType) { }
 
 class SpinnerViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 // infla layout dentro do container pai
 }
 }
  • 100. DELEGATE ADAPTERS | NEWS NewsDelegateAdapter.kt class NewsAdapterDelegate : ViewTypeDelegateAdapter {
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {
 holder as NewsViewHolder
 holder.bind(item as RedditNewsItem)
 }
 
 class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 
 fun bind(item : RedditNewsItem) = with(itemView) {
 img_thumbnail.loadImgUrl(item.thumbnail)
 description.text = item.title
 author.text = item.author
 comments.text = "${item.commentsNumber} comments"
 }
 }
 }
  • 101. DELEGATE ADAPTERS | NEWS NewsDelegateAdapter.kt class NewsAdapterDelegate : ViewTypeDelegateAdapter {
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {
 holder as NewsViewHolder
 holder.bind(item as RedditNewsItem)
 }
 
 class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 
 fun bind(item : RedditNewsItem) = with(itemView) {
 img_thumbnail.loadImgUrl(item.thumbnail)
 description.text = item.title
 author.text = item.author
 comments.text = "${item.commentsNumber} comments"
 }
 }
 }
  • 102. DELEGATE ADAPTERS | NEWS NewsDelegateAdapter.kt class NewsAdapterDelegate : ViewTypeDelegateAdapter {
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {
 holder as NewsViewHolder
 holder.bind(item as RedditNewsItem)
 }
 
 class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 
 fun bind(item : RedditNewsItem) = with(itemView) {
 img_thumbnail.loadImgUrl(item.thumbnail)
 description.text = item.title
 author.text = item.author
 comments.text = "${item.commentsNumber} comments"
 }
 }
 } Smart cast
  • 103. DELEGATE ADAPTERS | NEWS NewsDelegateAdapter.kt class NewsAdapterDelegate : ViewTypeDelegateAdapter {
 override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder = NewsViewHolder(parent)
 
 override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: ViewItem) {
 holder as NewsViewHolder
 holder.bind(item as RedditNewsItem)
 }
 
 class NewsViewHolder(parent : ViewGroup) : RecyclerView.ViewHolder
 (parent.inflate(R.layout.news_item_loading)) {
 
 fun bind(item : RedditNewsItem) = with(itemView) {
 img_thumbnail.loadImgUrl(item.thumbnail)
 description.text = item.title
 author.text = item.author
 comments.text = "${item.commentsNumber} comments"
 }
 }
 }
  • 104. DELEGATE ADAPTERS | NEWS - Carregando imagem no bind - Extension functions 
 fun ImageView.loadImgUrl(imageUrl: String?) {
 if (imageUrl.isNullOrEmpty()) {
 Picasso.with(context).load(R.mipmap.ic_launcher).into(this)
 } else {
 Picasso.with(context).load(imageUrl).into(this)
 }
 }
  • 106. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 override fun onActivityCreated(savedInstanceState: Bundle?) {
 // …
 val newsAdapter = NewsAdapter()
 newsList.adapter = newsAdapter
 
 if (savedInstanceState == null) {
 newsAdapter.addNews(mockData())
 }
 }
 
 private fun mockData() : List<RedditNewsItem> {
 val news = mutableListOf<RedditNewsItem>()
 
 for (i in 1..10) {
 news.add(RedditNewsItem(
 "Author $i",
 "Title $i",
 "http://lorempixel.com/200/200/technics/$i", // thumbnail
 i // number of comments
 ))
 }
 
 return news
 }
 }
  • 107. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 override fun onActivityCreated(savedInstanceState: Bundle?) {
 // …
 val newsAdapter = NewsAdapter()
 newsList.adapter = newsAdapter
 
 if (savedInstanceState == null) {
 newsAdapter.addNews(mockData())
 }
 }
 }
  • 108. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 override fun onActivityCreated(savedInstanceState: Bundle?) {
 // …
 val newsAdapter = NewsAdapter()
 newsList.adapter = newsAdapter
 
 if (savedInstanceState == null) {
 newsAdapter.addNews(mockData())
 }
 }
 }
  • 109. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 override fun onActivityCreated(savedInstanceState: Bundle?) {
 // …
 val newsAdapter = NewsAdapter()
 newsList.adapter = newsAdapter
 
 if (savedInstanceState == null) {
 newsAdapter.addNews(mockData())
 }
 }
 
 private fun mockData() : List<RedditNewsItem> {
 val news = mutableListOf<RedditNewsItem>()
 
 for (i in 1..10) {
 news.add(RedditNewsItem(
 "Author $i",
 "Title $i",
 "http://lorempixel.com/200/200/technics/$i", // thumbnail
 i // number of comments
 ))
 }
 
 return news
 }
 }
  • 110. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 private fun mockData() : List<RedditNewsItem> {
 val news = mutableListOf<RedditNewsItem>()
 
 for (i in 1..10) {
 news.add(RedditNewsItem(
 "Author $i",
 "Title $i",
 "http://lorempixel.com/200/200/technics/$i", // thumbnail
 i // number of comments
 ))
 }
 return news
 }
 }
  • 111. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 private fun mockData() : List<RedditNewsItem> {
 val news = mutableListOf<RedditNewsItem>()
 
 for (i in 1..10) {
 news.add(RedditNewsItem(
 "Author $i",
 "Title $i",
 "http://lorempixel.com/200/200/technics/$i", // thumbnail
 i // number of comments
 ))
 }
 return news
 }
 }
  • 112. ADICIONANDO ALGUNS DADOS MOCK class NewsFragment : Fragment() {
 // …
 private fun mockData() : List<RedditNewsItem> {
 val news = mutableListOf<RedditNewsItem>()
 
 for (i in 1..10) {
 news.add(RedditNewsItem(
 "Author $i",
 "Title $i",
 "http://lorempixel.com/200/200/technics/$i", // thumbnail
 i // number of comments
 ))
 }
 return news
 }
 }
  • 115. OUTRAS DICAS | CLICK LISTENERS myButton.setOnClickListener { navigateToDetail() }
  • 116. OUTRAS DICAS | OPTION MENU override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { R.id.action_settings -> consume { navigateToSettings() } R.id.nav_camera -> drawer.consume { navigateToCamera() } R.id.nav_gallery -> drawer.consume { loadGallery() } R.id.nav_slideshow -> drawer.consume { loadSlideshow() } else -> super.onOptionsItemSelected(item) }
  • 117. OUTRAS DICAS | OPTION MENU inline fun consume(f: () -> Unit): Boolean { f() return true } inline fun DrawerLayout.consume(f: () -> Unit): Boolean { f() closeDrawers() return true }
  • 118. OUTRAS DICAS | LAMBDAS view.postDelayed({ doWhatever() }, 200)
 
 
 Thread().run { // Running in a thread }
  • 119. OUTRAS DICAS | COLLECTIONS return parsedContacts.filter { it.name != null && it.image != null } .sortedBy { it.name } .map { Contact(it.id, it.name!!, it.image!!) }
  • 120. OUTRAS DICAS | ANKO - DSL - Useful Helpers
  • 121. OUTRAS DICAS | ANKO - DSL override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) verticalLayout { padding = dip(30) editText { hint = "Name" textSize = 24f } editText { hint = "Password" textSize = 24f } button("Login") { textSize = 26f // usando tamanho em SP } } }
  • 122. OUTRAS DICAS | ANKO - DSL - Useful Helpers
  • 123. OUTRAS DICAS | ANKO - Useful Helpers - Fazer ligação makeCall(numeroTelefone) - Abrir browser browse(url)
 - Compartilha texto share(text, [assunto])
 - Enviar email email(email, [assunto], [texto])
 - Abrir activity startActivity<SomeOtherActivity>("id" to 5)
  • 124. OUTRAS DICAS | ANKO - Useful Helpers async() { // Faz algo em background uiThread { // Volta para main thread } }
  • 125. LINKS Kotlin Lang: - https://kotlinlang.org/ Kotlin Roadmap - http://go.arctouch.com/kotlin-roadmap
  • 127. OBRIGADO. Big Brains Wanted Join our team! Go to arctouch.com/brjobs Visit our booth to win an Apple Watch.