Kotlin
Què és?
Llenguatge pensat per substituir Java com a llenguatge multiplataforma. Te caracteristiques més modernes com a llenguatge però compila igualment a ByteCode de JVM. Com comparteixen el format binari, ambdós llenguatges es poden cridar entre ells com si fossin crides natives, el que els fa totalment interoperables.
Fortament tipat pero automàtic
Les variables són fortament tipades com el Java. Pero no és necesari declarar els tipus sempre. Sovint els tipus es poden deduir del context.
Explicit casts y.asX()
Smart casts: Si abans d'un bloc de codi, ens assegurem que sigui quelcom ho sera
var a: A = whatever
if (a is B) {
Aquí podem fer servir a com si fos un B.
}
var optional: A? = whatever
if (a != null) {
Aquí podem fer servir a sense que sigui A i no A?
}
Tipus bàsics
Numèrics
Només els literals es converteixen de forma implicita
a un altre tipus numèric.
Per convertir dos variables o expressions
cal cridar el mètode .toType
corresponent.
On Type seria qualsevols dels tipus:
- Sencers:
Byte
(8b),Short
(16b),Int
(32b),Long
(64b) - Positius:
UByte
(8b),UShort
(16b),UInt
(32b),ULong
(64b) (Kotlin>=1.5) - Decimals:
Float
,Double
Podem fer servir suffixos per forçar el tipus del literal.
l
força Longu
força Unsingedf
força Float (a un Double)
Es pot fer servir l'underline com a separador de millars o bytes
Es poden fer servir prefixos 0b
o 0x
per binari i hexadecimal.
Només els literals es converteixen de forma implícita perque
es comproven en complilació.
En altres escenarios s'ha de fer de forma explícita amb els
metodes .toType()
: toInt()
, toByte()
...
Integer
és el tipus java encapsulat.
Els nadius es mencionen com kotlin.Int,
els de java com a java.Integer.
TODO: Conversió implícita?
Els operadors de bitwise son operadors infixos amb nom.
shl
, shr
, ushl
, inv
, `
Boleans
- El tipus es
Boolean
- Els literals son
true
yfalse
. - Els operadors, els de C:
&&
,||
y!
.
String
- Els literals per caracters
Char
van entre cometes simples'a'
. - Els literals per textos
String
van entre cometes dobles"text"
. - Es poden fer interpolacions amb
"$variable"
o d'expresions amb"${3+3}"
. - Un string es pot sumar
+
amb qualsevol cosa que tinguitoString
. - Les cometres dobles triples es fan servir per literals multi linia.
- Utilitat `.trimMargin(delimiter="|") es pot fer servir per ignorar l'indentat.
- TODO: Hi havia un altre per simplement treure la indentació sense signe.
- Prefix dolars a un text serveix per dir quants dolars calen per activar l'interpolacio.
$$"$${aixo s'interpola} $aixo no"
`$$$"$${aixo tampoc}" "%+05.3d".format(1.432)
"%s capitalized is %1\$S".format("hola")
Null safety
- Tipus nulables:
String
no pot sernull
,String?
pot ser-ho.- un no nullable pot assignar-se a un nullable pero no pas al revés.
if (var == null)
- Crida nulla
?.
:nullable?.method()
- Si nullable es null, el mètode no es crida i retorna null`
- Coalesce (elvis) operator
?:
- nullable ?: "default"
- L'expressió retorna el valor de nullable pero si es
null
retorna"default"
- Idioma
.?let {...}
- el block s'executa només si el receptor no es null
- El receptor dintre del block es pot referir com a
it
Functors
- declarats com a
myFunctor: (String) -> Boolean
- Lambdas { param, param2 -> body }
- Si no es defineixen parameters implicitament
it
- Function references with
::
as prefix - The last sentence of a lambda is the return value
-
If the lambda is the last parameter it can be placed outside the calling parenthesis
myFunction(1) {...}
-
object.apply(f)
: runs f with the object as this (so any variable is an attribute and function a method)
Puzzling syntax twist
X.method({})
can be rewriten as X method {}
only if method has a single parameter and the parameter is a block.
thats why we find code like:
Full featured enums: Sealed classes
sealed class
restricts inheritance to the subclases defined within its body. It can be used as power enums having attributes.
sealed class Event {
object Started : Event() // singleton class
object Ready : Event()
data class Failed(val error: String) : Event()
}
val event1: Event = Event.Started
val event2: Event = Event.Ready
val event3: Event = Event.Failed("An error")
if (event3 is Event.Ready) {
println(event3.error) // Safe cast! kotlin knows you checked already the type
}
(event3 as Event.Failed).error // 'as' will raise if bad cast
event3 as? Event.Failed).?let { it.error } // 'as?' returns null on bad cast
RepositoryEvent.UpdateReady
Coroutines
Coroutines are task to be run within threads. Let you write async non-blocking code in a sequential style (or not so...)
Coroutine Scope:
- A manager for a set of coroutines.
- Defines a context.
-
Defines it's life cycle.
-
launch {}
starts the block as a new coroutine- TOASK: is a method of a Scope
-
Dispatcher decide a que thread van ciertas coroutinas
-
TOASK: Relacion entre dispatcher y scope
-
Dispatchers.Main — runs on Android’s main UI thread.
- Dispatchers.IO — optimized for blocking IO tasks (network, file).
- Dispatchers.Default — for CPU-intensive tasks.
- Unconfined — starts coroutine in current thread but can resume in different thread.
- Test dispatcher — special dispatcher used in tests (runTest), controlling virtual time and execution order.
- Funcion
suspend
withContext(Dispatchers.Default) {}
Ejecuta el bloque en un grupo de threads concretos
-
The context
Get app info
val packageName = context.packageName val appInfo = context.applicationInfo
Acces resources:
val appName = context.getString(R.string.app_name) val color = ContextCompat.getColor(context, R.color.primary)
Start activities:
val intent = Intent(context, SettingsActivity::class.java) context.startActivity(intent)
Access preferences
val prefs = context.getSharedPreferences("app_settings", Context.MODE_PRIVATE) val darkMode = prefs.getBoolean("dark_mode", false)
Inflate layouts
val view = LayoutInflater.from(context).inflate(R.layout.item_station, parent, false)
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
Flow
Unit
Unit is like None in python. - A void value but you can pass it, return it...
In Python None is also used as empty optional value.
Not Unit. We use null
for that.
null
missing optional objectUnit
no meaningfull value