In deze driedelige serie hebben we uitgebreid gekeken naar Kotlin, een moderne programmeertaal voor Android-apps die wordt uitgevoerd in de Java Virtual Machine (JVM).
Hoewel Kotlin niet de enige alternatieve programmeertaal is die is ontworpen om op de JVM te worden uitgevoerd, heeft het toch veel te bieden aan Android-ontwikkelaars. Dus als je je onlangs gefrustreerd voelt door het Java-gedeelte van de Android-ontwikkeling, dan kun je overwegen om Kotlin een kans te geven.
In de eerste twee tranches hebben we het volgende behandeld:
Java vs. Kotlin: Moet je Kotlin gebruiken voor Android-ontwikkeling? In dit inleidende artikel hebben we gekeken naar wat Kotlin Android-ontwikkelaars te bieden heeft, evenals enkele potentiële nadelen waarvan u op de hoogte moet zijn voordat u beslist of Kotlin geschikt voor u is.
Codering Functionele Android-apps in Kotlin: Aan de slag. In dit bericht hebben we gekeken hoe Android Studio is geconfigureerd om Kotlin-code te ondersteunen, een Android-app is gemaakt die volledig in Kotlin is geschreven, die ons vertrouwd maakte met de basissyntaxis van Kotlin en die zelfs zag hoe overschakelen naar Kotlin kan betekenen dat je nooit nog een andere hoeft te schrijven findViewById
nog een keer.
Nu je in een positie bent waar je de Java-gedeelten van je projecten kunt vervangen door Kotlin-code met hetzelfde eindresultaat, gaan we verder en kijken we naar een aantal gebieden waar Kotlin de voordeel over Java.
In dit laatste deel gaan we enkele van de meer geavanceerde Kotlin-functies verkennen waarmee je taken kunt uitvoeren die veel meer uitgebreid zijn in Java, of niet haalbaar zijn met alleen Java..
Aan het einde van dit artikel, weet je hoe je Kotlin moet gebruiken om een ton boilerplate code uit je projecten te trimmen, bestaande klassen uit te breiden met nieuwe functionaliteit, en die frustrerend te maken NullPointerException
behoort tot het verleden.
Hoe vaak ben je een A tegengekomen? NullPointerException
tijdens het testen van uw code? Vandaag is het vrij duidelijk dat het toestaan van ontwikkelaars om null toe te wijzen aan een objectreferentie niet de het beste ontwerpkeuze! Pogingen om een objectreferentie met een nulwaarde te gebruiken, vormen een enorme bron van fouten in veel verschillende programmeertalen, waaronder Java. Eigenlijk, NullPointerException
is zo'n grote bron van ergernis geweest dat Java 8 het heeft toegevoegd @NonNull
annotatie specifiek om deze fout in zijn type systeem te verhelpen.
Het probleem ligt in het feit dat Java u toestaat om elke variabele van een verwijzingstype op nul in te stellen, maar als u op enig moment een referentie probeert te gebruiken die naar nul wijst, dan weet de variabele niet waar hij moet kijken omdat het object bestaat niet echt. Op dit punt kan de JVM niet doorgaan met het normale pad van uitvoering - uw toepassing zal crashen en u zult een NullPointerException
. Als u probeert een methode op een nulreferentie aan te roepen of een veld van een nulreferentie probeert te openen, activeren beide a NullPointerException
.
Als je de pijn hebt meegemaakt NullPointerException
s (en niet wij allemaal op een gegeven moment?) dan is er goed nieuws: nulveiligheid is geïntegreerd in de Kotlin-taal. De Kotlin-compiler staat niet toe dat u een nulwaarde toewijst aan een objectreferentie, omdat deze specifiek uw code controleert op de aanwezigheid van mogelijke nulobjecten tijdens de compilatie. Als de Kotlin-compiler detecteert dat een NullPointerException
kan tijdens runtime worden gegooid, dan zal uw code tijdens het compileren mislukken.
Het nulveilige ontwerp van Kotlin betekent dat u (bijna) nooit nul situaties zult tegenkomen en NullPointerException
s afkomstig van de Kotlin-code. De enige uitzondering is als u een trigger activeert NullPointerException
door verkeerd een van de speciale operatoren van Kotlin te gebruiken, of als u een van deze operatoren gebruikt om opzettelijk een a te activeren NullPointerException
(we zullen operators later in dit artikel gedetailleerder bekijken).
In Kotlin worden alle variabelen standaard als niet-nulbaar beschouwd, dus pogingen om een nulwaarde aan een variabele toe te wijzen, resulteren in een compilatiefout. Het volgende compileert bijvoorbeeld niet:
var voorbeeld: String = null
Als u wilt dat een variabele een nulwaarde accepteert, moet u die variabele expliciet als nullabel markeren. Dit is precies het tegenovergestelde van Java, waar elk object standaard als nullab beschouwd wordt, wat een groot deel van het waarom is NullPointerException
s zijn zo gewoon in Java.
Als u expliciet wilt aangeven dat een variabele een null-waarde kan accepteren, moet u een. Toevoegen ?
naar het variabele type. Bijvoorbeeld het volgende zullen compileren:
var example: String? = null
Wanneer de compiler dit soort declaratie ziet, erkent het dat dit een variabele is die nihil is en deze een beetje anders behandelt, met name het voorkomen dat u een methode aanroept of toegang tot een eigenschap op deze niet-te-referente referentie, zodat u opnieuw die vervelende NullPointerExceptions kunt vermijden . Het volgende compileert bijvoorbeeld niet:
var example: String? = null example.size
Hoewel het ontwerp van Kotlin betekent dat het moeilijk is om NullPointerExceptions afkomstig van Kotlin-code tegen te komen, als uw project een combinatie van Kotlin en Java bevat, kunnen de Java-gedeelten van uw project nog steeds een bron van NullPointerExceptions zijn.
Als je werkt met een mix van Kotlin- en Java-bestanden (of misschien moet je specifiek null-waarden invoeren in je Kotlin-code) dan bevat Kotlin een reeks speciale operaties die zijn ontworpen om je te helpen bij het omgaan met eventuele nulwaarden die je tegenkomt.
De operator voor veilig bellen ?.
geeft u een manier om om te gaan met verwijzingen die mogelijk een nulwaarde kunnen bevatten, terwijl u ervoor moet zorgen dat elke aanroep naar deze referentie niet resulteert in een NullPointerException
.
Wanneer u een Safe Call-operator toevoegt aan een referentie, wordt die referentie getest op een nulwaarde. Als de waarde null is, wordt null geretourneerd, anders wordt de objectreferentie gebruikt zoals u deze oorspronkelijk had bedoeld. Hoewel u hetzelfde effect kunt bereiken met een als
verklaring, de Safe Call-operator stelt u in staat om hetzelfde werk in veel minder code uit te voeren.
Het volgende komt bijvoorbeeld terug een maat
alleen als een
is niet null anders wordt null geretourneerd:
een maat
U kunt ook Safe Call-operators aan elkaar koppelen:
val nummer = persoon? .address? .street? .nummer
Als een van de expressies in deze reeks null is, is het resultaat null, anders is het resultaat de gevraagde waarde.
Soms heb je een expressie die mogelijk een ongeldige waarde kan bevatten, maar je wilt er geen gooien NullPointerException
zelfs als deze waarde doet blijken nul te zijn.
In dergelijke situaties kunt u de Elvis-operator van Kotlin gebruiken ?:
om een alternatieve waarde te bieden die wordt gebruikt wanneer de waarde nul blijkt te zijn, wat ook een goede manier is om de verspreiding van null-waarden in uw code te voorkomen.
Laten we eens kijken naar een voorbeeld van de Elvis-operator in actie:
fun setName (name: String?) username = name?: "N / A"
Hier, als de waarde links van de Elvis-operator is niet null dan wordt de waarde van de linkerkant geretourneerd (naam
). Maar als de waarde links van de Elvis-operator is null dan wordt de uitdrukking rechts weergegeven, wat in dit geval het geval is N / A
.
Als je je Kotlin-code ooit wilt dwingen om een Java-stijl NullPointerException te gebruiken, kun je de !!
operator. Bijvoorbeeld:
val nummer = firstName !!. lengte
Hier gebruiken we de !!
exploitant om te beweren dat het Voornaam
variabele is niet nul. Zolang Voornaam
bevat een geldige referentie, dan wordt het variabelenummer ingesteld op de lengte
van de string. Als Voornaam
bevat geen geldige referentie, dan gooit Kotlin een NullPointerException
.
Een lambda-uitdrukking vertegenwoordigt een anonieme functie. Lambda's zijn een goede manier om de hoeveelheid code te verminderen die nodig is om sommige taken uit te voeren die altijd voorkomen in Android-ontwikkeling, bijvoorbeeld het schrijven van luisteraars en callbacks.
Java 8 heeft native lambda-expressies geïntroduceerd en deze worden nu ondersteund in Android Nougat. Hoewel deze functie niet iets is dat uniek is voor Kotlin, is het toch de moeite waard om ernaar te kijken. Plus, als u werkt aan een project dat zowel Kotlin- als Java-code bevat, kunt u nu Lambda-expressies gebruiken voor uw hele project!
Een lambda-expressie bestaat uit een set parameters, een lambda-operator (->
) en een functielichaam, gerangschikt in het volgende formaat:
x: Int, y: Int -> x + y
Bij het construeren van lambda-expressies in Kotlin moet je de volgende regels in gedachten houden:
De lambda-expressie moet worden omringd door accolades.
Als de uitdrukking parameters bevat, moet u deze vóór de ->
pijlsymbool.
Als u met meerdere parameters werkt, moet u ze scheiden met komma's.
Het lichaam gaat achter de ->
teken.
Het belangrijkste voordeel van lambda-expressies is dat ze u in staat stellen om anonieme functies te definiëren en deze functies vervolgens onmiddellijk door te geven als een uitdrukking. Hiermee kun je veel algemene ontwikkeltaken beknopter uitvoeren dan je in Java 7 en eerder kon doen, omdat je niet langer de specificatie van de functie in een abstracte klasse of interface hoeft te schrijven. In feite is het ontbreken van lambda's in Java 7 en eerder een groot deel van waarom het schrijven van luisteraars en callbacks traditioneel zo onhandig was in Android.
Laten we een veelvoorkomend voorbeeld bekijken: een klik-luisteraar toevoegen aan een knop. In Java 7 en eerder zou dit meestal de volgende code vereisen:
button.setOnClickListener (nieuwe View.OnClickListener () @Override public void onClick (View v) Toast.makeText (this, "Button clicked", Toast.LENGTH_LONG) .show (););
Met Kotlin lambda-functies kunt u echter een kliklistener instellen met behulp van een enkele regel code:
button.setOnClickListener (view -> toast ("Knop geklikt"))
Dit is al veel beknopter en gemakkelijker te lezen, maar we kunnen verder gaan: als een functie een andere functie als laatste parameter gebruikt, kunt u deze buiten de haakjeslijst doorgeven:
button.setOnClickListener () toast ("Knop geklikt")
En als de functie slechts één parameter heeft die een functie is, kunt u de haakjes volledig verwijderen:
button.setOnClickListener toast ("Knop geklikt")
Net als bij C #, kun je met Kotlin nieuwe functionaliteit toevoegen aan bestaande klassen die je anders niet zou kunnen wijzigen. Dus als je denkt dat een klas een bruikbare methode mist, waarom dan niet zelf toevoegen, via een uitbreidingsfunctie?
U maakt een uitbreidingsfunctie door de naam van de klasse die u wilt uitbreiden voor te geven aan de naam van de functie die u aan het maken bent.
Bijvoorbeeld:
fun AppCompatActivity.toast (msg: String) Toast.makeText (this, msg, Toast.LENGTH_LONG) .show ()
Merk op dat de deze
sleutelwoord binnen de uitbreidingsfunctie komt overeen met de AppCompatActivity
bijvoorbeeld welke .geroosterd brood
wordt aangeroepen.
In dit voorbeeld hoeft u alleen het te importeren AppComptActivity
en Geroosterd brood
lessen in je .kt bestand en dan bent u klaar om het te bellen .
notatie op exemplaren van de uitgebreide klasse.
Als het gaat om Android-ontwikkeling, vindt u extensie-functies met name handig om te geven ViewGroups
het vermogen om zichzelf op te blazen, bijvoorbeeld:
leuke ViewGroup.inflate (@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View return LayoutInflater .from (context) .inflate (layoutRes, this, attachToRoot)
Dus in plaats van het volgende te moeten schrijven:
val view = LayoutInflater .van (bovenliggende) .inflate (R.layout.activity_main, parent, false)
U kunt eenvoudig uw uitbreidingsfunctie gebruiken:
val view = parent.inflate (R.layout.activity_main)
In Java is het maken van singletons meestal behoorlijk uitgebreid geweest, waardoor je een klasse met een privéconstructor moet maken en die instantie vervolgens als privéattribuut moet maken.
Het eindresultaat is meestal zoiets als dit:
openbare klasse Singleton private static Singleton singleton = new Singleton (); private Singleton () public static Singleton getInstance () return singleton;
In plaats van een klasse te declareren, kun je met Kotlin één enkel object definiëren, dat semantisch hetzelfde is als een singleton, in één regel code:
object KotlinSingleton
U kunt deze singleton dan meteen gebruiken, bijvoorbeeld:
object KotlinSingleton fun myFunction () [...] KotlinSingleton.myFunction ()
In dit artikel hebben we een diepgaand onderzoek gedaan naar het nulveilige ontwerp van Kotlin en hebben we gezien hoe je ervoor kunt zorgen dat je Android-projecten null-veilig blijven, zelfs als ze een combinatie van Java- en Kotlin-code bevatten door een reeks speciale operatoren te gebruiken. We hebben ook bekeken hoe je lambda-expressies kunt gebruiken om een aantal veel voorkomende ontwikkeltaken in Android te vereenvoudigen en hoe je nieuwe functionaliteit aan bestaande klassen kunt toevoegen..
Gecombineerd met wat we hebben geleerd in Deel 1: Java vs. Kotlin en Deel 2: Aan de slag, heb je nu alles wat je nodig hebt om effectieve Android-apps te bouwen met behulp van de Kotlin-programmeertaal.
Veel plezier met de Kotlin-taal, en waarom niet eens kijken naar enkele van onze andere cursussen en tutorials over Android-programmering?