Slide 1

Slide 1 text

MADRID · NOV 27-28 · 2015 Kotlin for Android Developers Antonio Leiva @lime_cl

Slide 2

Slide 2 text

http://plex.tv

Slide 3

Slide 3 text

http://antonioleiva.com

Slide 4

Slide 4 text

Let’s create a contacts App!

Slide 5

Slide 5 text

Contacts App https://github.com/antoniolg/kontacts

Slide 6

Slide 6 text

What is Kotlin?

Slide 7

Slide 7 text

What is Kotlin? • JVM based • Object-oriented functional language • Created by JetBrains (IntelliJ, Android Studio) • Simple,lightweight, interoperable

Slide 8

Slide 8 text

Let’s code!

Slide 9

Slide 9 text

Let’s code! Title Text Model

Slide 10

Slide 10 text

JAVA public class Contact {
 
 private final String name;
 private final String imageUrl;
 
 public Contact(String name, String imageUrl) {
 this.name = name;
 this.imageUrl = imageUrl;
 }
 
 public String getName() {
 return name;
 }
 
 public String getImageUrl() {
 return imageUrl;
 }
 }

Slide 11

Slide 11 text

JAVA public class Contact {
 
 …
 
 public String toString() {
 return String.format("name: %s; imageUrl: %s", name, imageUrl);
 }
 
 @Override public boolean equals(Object o) {
 if (o instanceof Contact) {
 Contact c = (Contact) o;
 return name.equals(c.getName()) && imageUrl.equals(c.getImageUrl());
 } else {
 return false;
 }
 }
 }

Slide 12

Slide 12 text

Properties KOTLIN Property = Field + Getter (+ Setter) val name: String val imageUrl: String

Slide 13

Slide 13 text

Constructor KOTLIN class Contact(name: String, imageUrl: String) { … }

Slide 14

Slide 14 text

Constructor KOTLIN class Contact(val name: String, val imageUrl: String) { … }

Slide 15

Slide 15 text

String templates KOTLIN override fun toString(): String {
 
 } 
 return "name: $name; imageUrl: $imageUrl"


Slide 16

Slide 16 text

Auto-Casting KOTLIN override fun equals(other: Any?) = when (other) {
 is Contact -> name == other.name 
 && imageUrl == other.imageUrl
 else -> false
 }

Slide 17

Slide 17 text

Null safety KOTLIN var artist: Artist? = null
 artist.print() var artist: Artist? = null
 artist?.print() won´t compile will do nothing if (artist != null) {
 artist.print()
 } Smart cast var artist: Artist? = null
 artist!!.print() will crash

Slide 18

Slide 18 text

Data Class KOTLIN data class Contact(val name: String, val imageUrl: String)

Slide 19

Slide 19 text

Data Class KOTLIN data class Contact(val name: String, val imageUrl: String) val (name, url) = contact

Slide 20

Slide 20 text

Let’s code! Title Text View Binding

Slide 21

Slide 21 text

View binding Java -> Butterknife

Slide 22

Slide 22 text

View binding Java -> Butterknife Kotlin -> Property delegation val recyclerView by lazy { findViewById(R.id.recycler) as RecyclerView }

Slide 23

Slide 23 text

View binding Java -> Butterknife Kotlin -> Property delegation val recyclerView by lazy { findViewById(R.id.recycler) as RecyclerView }

Slide 24

Slide 24 text

Kotlin Android Extensions Direct access to XML views using its id as property name activity_main.xml 
 
 
 


Slide 25

Slide 25 text

Kotlin Android Extensions Import synthetic properties import kotlinx.android.synthetic.activity_main.* Use the properties override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState) setContentView(R.id.main)
 } recycler.layoutManager = GridLayoutManager(this, 2)
 recycler.adapter = ContactsAdapter(contacts)


Slide 26

Slide 26 text

Kotlin Android Extensions Also works on views! import kotlinx.android.synthetic.view_item.view.* Use the properties class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
 
 fun bind(contact: Contact, listener: (Contact) -> Unit) {
 itemView.contactText.text = contact.name
 itemView.contactImage.loadUrl(contact.imageUrl)
 }
 }

Slide 27

Slide 27 text

Let’s code! Title Text Asynchrony

Slide 28

Slide 28 text

Asynchrony object: AsyncTask>(){
 override fun doInBackground(vararg params: Unit?): List {
 return GetContactsCommand().execute(this@MainActivity)
 }
 
 override fun onPostExecute(result: List) {
 if (!isFinishing)
 recycler.adapter = ContactsAdapter(result) { navigateToDetail(it) };
 }
 }

Slide 29

Slide 29 text

Anko https://github.com/JetBrains/anko

Slide 30

Slide 30 text

Anko • DSL to declare UIs in Kotlin verticalLayout {
 val name = editText()
 button("Say Hello") {
 onClick { toast("Hello, ${name.text}!") }
 }
 }

Slide 31

Slide 31 text

Anko • DSL to declare UIs in Kotlin • Useful functions and properties context.layoutInflater context.notificationManager
 context.sensorManager
 context.vibrator toast(R.string.message)
 longToast("Wow, such a duration")

Slide 32

Slide 32 text

Anko • DSL to declare UIs in Kotlin • Useful functions and properties • SQLite helpers

Slide 33

Slide 33 text

Anko • DSL to declare UIs in Kotlin • Useful functions and properties • SQLite helpers • Easy asynchrony

Slide 34

Slide 34 text

Anko async async {
 val contacts = GetContactsCommand().execute(ctx)
 uiThread {
 recycler.adapter = ContactsAdapter(contacts)
 }
 }

Slide 35

Slide 35 text

Let’s code! Title Text Navigate to Detail

Slide 36

Slide 36 text

Navigate to Detail private fun navigateToDetail(contact: Contact) {
 
 } 
 val intent = Intent(this, DetailActivity::class.java)
 intent.putExtra("name", contact.name)
 intent.putExtra("imageUrl", contact.imageUrl)
 startActivity(intent)


Slide 37

Slide 37 text

Navigate (with Anko) private fun navigateToDetail(contact: Contact) {
 
 } 
 startActivity("name" to contact.name,
 "imageUrl" to contact.imageUrl)


Slide 38

Slide 38 text

Let’s code! Title Text Extension functions

Slide 39

Slide 39 text

Extension functions override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
 val v = … return ViewHolder(v)
 }


Slide 40

Slide 40 text

Extension functions val v =

Slide 41

Slide 41 text

Extension functions val v = LayoutInflater

Slide 42

Slide 42 text

Extension functions val v = LayoutInflater .from(

Slide 43

Slide 43 text

Extension functions val v = LayoutInflater .from( parent.context)

Slide 44

Slide 44 text

Extension functions val v = LayoutInflater .from( parent.context) .inflate(R.layout.view_item,

Slide 45

Slide 45 text

Extension functions val v = LayoutInflater .from( parent.context) .inflate(R.layout.view_item, parent,

Slide 46

Slide 46 text

Extension functions val v = LayoutInflater .from( parent.context) .inflate(R.layout.view_item, parent, false)

Slide 47

Slide 47 text

Extension functions val v = LayoutInflater.from(parent.context) .inflate(R.layout.view_item, parent, false)


Slide 48

Slide 48 text

Extension functions val v = LayoutInflater.from(parent.context) .inflate(R.layout.view_item, parent, false)
 val v = parent.inflate(R.layout.view_item)

Slide 49

Slide 49 text

return LayoutInflater.from(context) .inflate(layoutRes, this,
 } Extension functions fun ViewGroup.inflate(layoutRes: Int ): View { false )

Slide 50

Slide 50 text

return LayoutInflater.from(context) .inflate(layoutRes, this,
 } Extension functions fun ViewGroup.inflate(layoutRes: Int ): View { ) attachToRoot: Boolean = false , attachToRoot

Slide 51

Slide 51 text

return LayoutInflater.from(context) .inflate(layoutRes, this,
 } Extension functions fun ViewGroup.inflate(layoutRes: Int ): View { ) attachToRoot: Boolean = false , attachToRoot viewGroup.inflate(R.layout.view_item)
 viewGroup.inflate(R.layout.view_item, false)
 viewGroup.inflate(R.layout.view_item, true)

Slide 52

Slide 52 text

return LayoutInflater.from(context) .inflate(layoutRes, this,
 } Extension functions fun ViewGroup.inflate(layoutRes: Int ): View { ) attachToRoot: Boolean = false , attachToRoot

Slide 53

Slide 53 text

Extension functions Picasso.with(contactImage.context).load(contact.imageUrl) .into(contactImage)

Slide 54

Slide 54 text

Extension functions Picasso.with(contactImage.context).load(contact.imageUrl) .into(contactImage) contactImage.loadUrl(contact.imageUrl)

Slide 55

Slide 55 text

Extension functions fun ImageView.loadUrl(url: String) {
 Picasso.with(context).load(url).into(this)
 }

Slide 56

Slide 56 text

Functional features

Slide 57

Slide 57 text

Functional features Lambdas

Slide 58

Slide 58 text

Lambdas function: (T) -> R

Slide 59

Slide 59 text

Lambdas public interface Callback {
 void invoke(T result);
 }
 
 public void asyncOperation(int value, Callback callback){
 ...
 callback.invoke(true);
 } JAVA asyncOperation(5, new Callback() {
 @Override public void invoke(Boolean result) {
 System.out.println("Result: " + result);
 }
 });

Slide 60

Slide 60 text

Lambdas fun asyncOperation(value: Int, callback: (Boolean) -> Unit) {
 ...
 callback(true)
 } asyncOperation(5) { result ->
 println("result: $result")
 }

Slide 61

Slide 61 text

Lambdas fun asyncOperation(value: Int, callback: (Boolean) -> Unit) {
 ...
 callback(true)
 } asyncOperation(5) { result ->
 println("result: $result")
 } asyncOperation(5) { println("result: $it") }

Slide 62

Slide 62 text

Lambdas asyncOperation(5) { println("result: $it") } asyncOperation(5, new Callback() {
 @Override public void invoke(Boolean result) {
 System.out.println("Result: " + result);
 }
 });

Slide 63

Slide 63 text

Lambdas recycler.adapter = ContactsAdapter(contacts) { navigateToDetail(it) }

Slide 64

Slide 64 text

Lambdas recycler.adapter = ContactsAdapter(contacts) { navigateToDetail(it) } class ContactsAdapter(val contacts: List, val listener: (Contact) -> Unit)

Slide 65

Slide 65 text

Lambdas recycler.adapter = ContactsAdapter(contacts) { navigateToDetail(it) } class ContactsAdapter(val contacts: List, val listener: (Contact) -> Unit) itemView.setOnClickListener { listener(contact) }

Slide 66

Slide 66 text

Functional features Collections

Slide 67

Slide 67 text

Collections • Iterable • Collection • List • Set • Map filter sort map zip dropWhile first firstOrNull last lastOrNull fold …

Slide 68

Slide 68 text

Collections val contacts = ArrayList()
 
 for (contact in parsedContacts) {
 if (contact.name != null && contact.image != null) {
 contacts.add(Contact(contact.name, contact.image))
 }
 }
 
 Collections.sort(contacts, { o1, o2 -> if (o1.name <= o2.name) -1 else 1 })

Slide 69

Slide 69 text

Collections parsedContacts .filter { it.name != null && it.image != null }
 .sortedBy { it.name }
 .map { Contact(it.name!!, it.image!!) }

Slide 70

Slide 70 text

Conclusion

Slide 71

Slide 71 text

Conclusion • Lightweight, simple and powerful • Simplifies Android Development • 1.0 Beta 2 -> Final version soon!

Slide 72

Slide 72 text

http://antonioleiva.com/book/ Kotlin for Android Developers • Create App from scratch • Step by step • Complete Kotlin coverage • Updated to latest version

Slide 73

Slide 73 text

http://antonioleiva.com/book/ ?