I den perfekte verdenen til Android er hovedspråket til Java veldig moderne, klart og elegant, du kan skrive mindre ved å gjøre mer, og hver gang en ny funksjon vises, kan utviklere bruke den ved å øke versjonen i Gradle . Ved å lage en fin app virker funksjonen fullstendig testbar, utvidbar og vedlikeholdbar. Aktivitetene våre er ikke for store og kompliserte, vi kan endre datakildene fra databasen til nettet uten for mange forskjeller og så videre. Høres bra ut? Dessverre er dette ikke i Android-verdenen ideelt. Google fortsetter å streve for perfeksjon, men vi vet alle at ideelle verdener ikke eksisterer. Derfor må vi hjelpe oss selv på den flotte reisen i Android-verdenen.
Så det første språket. Jeg tror Java ikke er mesteren av eleganse eller klarhet, og det er verken moderne eller uttrykksfullt (og jeg antar at du er enig). Ulempen er at under Android N er vi fortsatt begrenset til Java 6 (inkludert noen små deler av Java 7). Utviklere kan også legge ved RetroLambda å bruke lambdauttrykk i koden din, noe som er veldig nyttig når du bruker RxJava . På toppen av Android N kan vi bruke noe av den nyere Java 8-funksjonaliteten, men det er fortsatt den gamle tunge Java. Svært ofte hører jeg [Android-utviklere] (https://www.toptal.com/android) si 'Jeg skulle ønske Android ville støtte et finere språk, som iOS gjør med Swift.' Hva om jeg fortalte deg at du kan bruke et veldig hyggelig og enkelt språk, med null sikkerhet, lambdas og mange andre nye funksjoner? Velkommen til Kotlin.
Kotlin er et nytt språk (noen ganger kjent som Swift for Android), utviklet av teamet på JetBrains og nå er det i sin versjon 1.0.2. Det som gjør det nyttig i Android-utvikling er at det kompileres til JVM bytecode, og det kan også kompileres med JavaScript. Den er fullt kompatibel med Java, og Kotlin-koden kan enkelt konverteres til Java-kode og omvendt (det er en plugg inn av JetBrains). Dette betyr at Kotlin kan bruke ethvert rammeverk, bibliotek, etc., skrevet i Java. På Android er den integrert av Gradle. Hvis du har en eksisterende Android-applikasjon og vil implementere en ny funksjon i Kotlin uten å omskrive hele applikasjonen, er det bare å begynne å skrive i Kotlin så fungerer det.
Men hva er de 'flotte nye funksjonene'? La meg liste opp noen:
Fecha de crear Diversión(day: Int, month: Int, year: Int, hour: Int = 0, minute: Int = 0, second: Int = 0) { print('TEST', '$day-$month-$year $hour:$minute:$second') }
Fechacreación(1,2,2016) prints: ‘1-2-2016 0:0:0’ Fechacreación(1,2,2016, 12) prints: ‘1-2-2016 12:0:0’ Fechacreación(1,2,2016, minute = 30) prints: ‘1-2-2016 0:30:0’
Hvis en variabel kan være null, kompileres ikke koden med mindre vi tvinger den til. Følgende kode vil ha en feil: nullable Var kan være null:
var nullableVar: String? = “”; nullableVar.length;
For å kompilere må vi verifisere om det er null eller ikke:
if(nullableVar){ nullableVar.length }
Eller enda kortere:
nullableVar?.length
På denne måten, hvis nullableVar er null, skjer ingenting. Ellers kan vi merke variabelen som ikke-nullbar, uten spørsmålstegn etter type:
var nonNullableVar: String = “”; nonNullableVar.length;
Denne koden er kompilert, og hvis vi vil tildele null til ikke-NullableVar, vil kompilatoren vise en feil.
Elvis-operatøren er også veldig nyttig:
var stringLength = nullableVar?.length ?: 0
Så når nullableVar er null (så nullableVar? .Length resulterer i null), vil stringLength ha verdien 0.
I eksemplet ovenfor bruker jeg hvor når du definerer en variabel. Dette er foranderlig, vi kan omfordele det når vi vil. Hvis vi vil at denne variabelen skal være uforanderlig (i mange tilfeller burde vi det), bruker vi timer (som verdi, ikke variabel):
val immutable: Int = 1
Etter det vil ikke kompilatoren tillate oss å kartlegge til uforanderlig.
Vi vet alle hva en lambda er, så her skal jeg vise hvordan vi kan bruke den i Kotlin:
button.setOnClickListener({ view -> Log.d('Kotlin','Click')})
Eller hvis funksjonen er det eneste eller siste argumentet:
button.setOnClickListener { Log.d('Kotlin','Click')}
Utvidelser er en veldig nyttig språkfunksjon, takket være at vi kan 'utvide' eksisterende klasser, selv når de er endelige eller vi ikke har tilgang til kildekoden.
For eksempel, for å få en rediger tekststrengverdi, i stedet for å skrive editText.text.toString () hver gang vi kan skrive funksjonen:
fun EditText.textValue(): String{ return text.toString() }
Eller enda kortere:
fun EditText.textValue() = text.toString()
Og nå, med hver forekomst av Rediger tekst :
editText.textValue()
Eller vi kan legge til en eiendom som returnerer det samme:
var EditText.textValue: String get() = text.toString() set(v) {setText(v)}
Noen ganger er det nyttig hvis vi vil legge til, multiplisere eller sammenligne objekter. Kotlin tillater overbelastning av: binære operatorer (pluss, minus, plusAssign, rekkevidde osv.), Arrayoperatører (get, set, get range, set range) og like og unary operasjoner (+ a, -a, etc. .
Hvor mange kodelinjer trenger du for å implementere en brukerklasse i Java med tre egenskaper: kopi, lik, hashCode Y toString ? I Kotlin trenger du bare en linje:
Usuario de Clase de Datos(nombre del val: String, apellido del val: String, edad del val: Int)
Denne dataklassen gir like (), hashCode (), og copy () metoder, og også toString (), som skriver ut brukeren som:
Usuario(nombre=John, apellido=Doe, edad=23)
Dataklassene gir også noen andre nyttige funksjoner og egenskaper som kan sees i Kotlin-dokumentasjonen.
Bruk Smørkniv eller Android-utvidelser, ikke sant? Hva om du ikke en gang trenger å bruke dette biblioteket, og etter å ha erklært visningene i XML, bruker du det bare fra koden etter IDen (som med XAML i C #):
loginBtn.setOnClickListener{}
import kotlinx.android.synthetic.main.activity_main.*
Kotlin har veldig nyttige [Anko-utvidelser] (https://github.com/Kotlin/anko) og med dette trenger du ikke å fortelle aktiviteten hva det er innloggingBtn , du vet det ganske enkelt ved å 'importere' xml:
interface CreateUserView : View { fun showEmptyNameError() /* show error when name is empty */ fun showEmptySurnameError() /* show error when surname is empty */ fun showUserSaved() /* show user saved info */ fun showUserDetails(user: User) /* show user details */ }
Det er mange andre nyttige ting i Anko, inkludert startaktiviteter, mellomaktiviteter og så videre. Dette er ikke hovedmålet til Anko - det er designet for å enkelt lage kodeoppsett. Så hvis du trenger å lage et programmeringsoppsett, er dette den beste måten.
Dette er bare en kort oversikt over Kotlin. Jeg anbefaler å lese bloggen til Antonio Leiva og boka hans - Kotlin for Android-utviklere , og selvfølgelig det offisielle Kotlin-nettstedet.
Et fint, kraftig og tydelig språk er ikke nok. Det er veldig enkelt å skrive rotete apper med alle språk uten god arkitektur. Android-utviklere (hovedsakelig de som nettopp har begynt, men også de mer avanserte) gir ofte Activity ansvaret for alt rundt seg. Aktiviteten (eller utdrag, eller annen visning) laster ned data, lagrer for å sende, presenterer den, reagerer på brukerinteraksjoner, redigerer data og administrerer alle barnevisninger. . . Og mange ganger mye mer. Det er for mye for objekter så ustabile som aktiviteter eller fragmenter (bare roter skjermen og aktiviteten sier 'Bye ...').
En veldig god idé er å isolere meningenes ansvar og gjøre dem så dumme som mulig. Visninger (aktiviteter, utdrag, egendefinerte visninger eller hva som helst som presenterer data på skjermen) skal være eneansvarlig for å administrere undervisningene sine. Synspunktene skal ha presentatører, som kommuniserer med modellen og forteller dem hva de skal gjøre. Dette er kort sagt mønsteret Model-View-Presentator (for meg skal det hete Model-Presentator-View for å vise sammenhenger mellom lag).
'Hei, jeg vet om noe sånt, og det heter MVC!' tror du ikke? Nei, MVP er ikke det samme som MVC. I MVC-mønsteret kan synet ditt kommunisere med modellen. Mens du bruker MVP, tillater du ikke kommunikasjon mellom disse to lagene, den eneste måten Utsikt kan kommunisere med Modell er gjennom Presentatør . Den eneste som Utsikt vite om Modell det kan være datastrukturen. Utsikt vet hvordan, for eksempel, å vise Bruker , men vet ikke når. Her er et enkelt eksempel:
Synet vet at “Jeg er aktivitet, jeg har to EditTexts og en knapp. Når noen klikker på knappen, må jeg fortelle programlederen min, og jeg overfører verdiene til EditTexts . Og det er det, jeg kan sove til neste klikk eller presentatøren forteller meg hva jeg skal gjøre ”.
Presentatør den vet at et sted er en visning, og den vet hvilke operasjoner denne visningen kan utføre. Du vet også at når du mottar to strenger, må du opprette brukeren fra disse to strengene og sende data til modellen for å lagre, og hvis den lagres vellykket, fortell visningen 'Vis suksessinfo'.
Modellen vet bare hvor dataene er, hvor de må lagres, og hvilke operasjoner som må utføres på dataene.
Programmer skrevet i MVP er enkle å teste, vedlikeholde og gjenbruke. En ren programleder skal ikke vite noe om Android-plattformen. Det må være en ren klasse av (eller Kotlin, i vårt tilfelle) Java. Takket være dette kan vi bruke programlederen vår i andre prosjekter. Vi kan også enkelt skrive enhetstester, teste hver for seg Modell , Utsikt Y Presentatør .
MVP-mønsteret fører til en bedre og mindre kompleks kodebase ved å holde brukergrensesnittet og forretningslogikken virkelig atskilt.Litt avvik: MVP bør være en del av Onkel Bobs rene arkitektur for å gjøre applikasjoner enda mer fleksible og godt designet. Det skal jeg prøve å skrive om neste gang.
Dette er nok teori, la oss se litt kode! Vel, la oss prøve å lage et enkelt program. Hovedmålet med dette programmet er å opprette en bruker. Det første skjermbildet vil ha to EditTexts (første og siste) og en (Lagre) -knapp. Etter å ha tastet inn for- og etternavnet og klikket på 'Lagre', skal applikasjonen vise 'Bruker er lagret' og gå til neste skjermbilde, der det lagrede for- og etternavnet vises. Når for- eller etternavnet er tomt, bør ikke applikasjonen lagre brukeren, og det viser en feil som indikerer hva som er galt.
Den første tingen å gjøre etter å ha opprettet prosjektet Android Studio er å konfigurere Kotlin. Du burde installer Kotlin-plugin og etter omstart, i Verktøy> Kotlin kan du klikke på 'Konfigurer Kotlin i prosjekt'. IDE vil legge til Kotlin-avhengigheter i Gradle. Hvis du har noen eksisterende kode, kan du enkelt konvertere den til Kotlin (Ctrl + Shift + Alt + K eller Encode> Convert Java File to Kotlin). Hvis noe ikke fungerer og prosjektet ikke kompileres, eller Gradle ikke ser Kotlin, kan du sjekke applikasjonskoden som er tilgjengelig på GitHub.
Kotlin samarbeider ikke bare godt med Java-rammer og biblioteker, det lar deg fortsette å bruke de fleste av de samme verktøyene som du allerede er kjent med.Nå som vi har et prosjekt, la oss starte med å lage vår første visning: Opprett brukervisning . Denne visningen må ha funksjonene som er nevnt ovenfor, så vi kan skrive et grensesnitt for det:
interface View
Som du kan se, ligner Kotlin Java på å erklære funksjoner. Alt er funksjoner som ikke returnerer noe, og de siste har en parameter. Dette er forskjellen, parametertypen kommer etter navnet. View-grensesnittet er ikke Android: det er vårt enkle, tomme grensesnitt:
interface Presenter { var view: T? fun onDestroy(){ view = null } }
Grensesnittet til Presentatør Basic må ha en egenskap av typen visning, og i det minste i metoden (onDestroy for eksempel), der denne egenskapen vil bli satt til null:
interface CreateUserPresenter: Presenter { fun saveUser(name: String, surname: String) }
Her kan du se en annen funksjon i Kotlin: du kan erklære egenskaper på grensesnitt og også implementere metoder der.
Våre CreateUserView trenger å kommunisere med CreateUserPresenter . Den eneste tilleggsfunksjonen denne programlederen trenger er lagre bruker med to strengargumenter:
data class User(val name: String, val surname: String)
Vi trenger også en definisjon av modell - den er nevnt tidligere i klassetypen:
class CreateUserPresenterImpl(override var view: CreateUserView?): CreateUserPresenter { override fun saveUser(name: String, surname: String) { } }
Etter å ha erklært alle grensesnittene, kan vi begynne å implementere.
CreateUserPresenter vil bli implementert i CreateUserPresenterImpl :
CreateUserPresenterImpl(override var view: CreateUserView?)
Første linje, med klassedefinisjon:
class MainActivity : AppCompatActivity(), CreateUserView { private val presenter: CreateUserPresenter by lazy { CreateUserPresenterImpl(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) saveUserBtn.setOnClickListener{ presenter.saveUser(userName.textValue(), userSurname.textValue()) /*use of textValue() extension, mentioned earlier */ } } override fun showEmptyNameError() { userName.error = getString(R.string.name_empty_error) /* it's equal to userName.setError() - Kotlin allows us to use property */ } override fun showEmptySurnameError() { userSurname.error = getString(R.string.surname_empty_error) } override fun showUserSaved() { toast(R.string.user_saved) /* anko extension - equal to Toast.makeText(this, R.string.user_saved, Toast.LENGTH_LONG) */ } override fun showUserDetails(user: User) { } override fun onDestroy() { presenter.onDestroy() } }
Det er en konstruktør, vi bruker den til å tildele visningsegenskapen, definert i grensesnittet.
Hoved aktivitet , som er vår CreateUserView implementering, trenger en referanse til CreateUserPresenter :
private val presenter: CreateUserPresenter by lazy { CreateUserPresenterImpl(this) }
I begynnelsen av eksemplet definerer vi presentatøren vår:
override fun saveUser(name: String, surname: String) { val user = User(name, surname) when(UserValidator.validateUser(user)){ UserError.EMPTY_NAME -> view?.showEmptyNameError() UserError.EMPTY_SURNAME -> view?.showEmptySurnameError() UserError.NO_ERROR -> { UserStore.saveUser(user) view?.showUserSaved() view?.showUserDetails(user) } } }
Det er definert som uforanderlig (val), og det er opprettet av lat delegat, som vil bli tildelt første gang det er behov for det. På den annen side er vi sikre på at den ikke vil være null (ingen spørsmålstegn etter definisjonen).
Når brukeren klikker Lagre-knappen, sender View informasjonen til presentatøren med EditTexts-verdier. Når dette skjer, må brukeren lagres, så vi må implementere saveUser-metoden i Presenter (og noen av modellfunksjonene):
enum class UserError { EMPTY_NAME, EMPTY_SURNAME, NO_ERROR } object UserStore { fun saveUser(user: User){ //Save user somewhere: Database, SharedPreferences, send to web... } } object UserValidator { fun validateUser(user: User): UserError { with(user){ if(name.isNullOrEmpty()) return UserError.EMPTY_NAME if(surname.isNullOrEmpty()) return UserError.EMPTY_SURNAME } return UserError.NO_ERROR } } Lo más interesante aquí es *UserValidator.* Mediante el uso de la palabra objeto, podemos crear una clase *Singleton*, sin preocupaciones de hilos, constructores privados y así sucesivamente. Adicionalmente: en el método validateUser (usuario), existe con (usuario) {} expresión. El código dentro de dicho bloque se ejecuta en contexto de objeto, se pasa con el nombre y el apellido son las propiedades del Usuario. También hay otra pequeña cosa. Todo el código anterior, de enum a *UserValidator*, la definición se coloca en un archivo (la definición de clase de usuario también está aquí). Kotlin no te obliga a tener cada clase pública en un solo archivo (o nombre de la clase exactamente como archivo). Por lo tanto, si tienes algunos fragmentos cortos de código relacionados con (clases de datos, extensiones, funciones, constantes - Kotlin no requiere clase para función o constante), puedes colocarlos en un solo archivo en lugar de propagarlos a través de todos los archivos del proyecto. Cuando un usuario se guarda, nuestra aplicación debería mostrarlo. Necesitamos otra vista: puede ser cualquier vista de Android, vista personalizada, fragmento o actividad. Elige la Actividad. Por lo tanto, vamos a definir la interfaz de*UserDetailsView*. Puede mostrar al usuario, pero también debe mostrar un error cuando el usuario no está presente: ~~~ kotlin interface UserDetailsView { fun showUserDetails(user: User) fun showNoUserError() }
Når en bruker er opprettet, sendes den til UserValidator for å kontrollere gyldigheten. Deretter, basert på resultatet av valideringen, kalles den riktige metoden. Når () {} -konstruksjonen er den samme som switch / case i Java. Men det er kraftigere - Kotlin tillater ikke bare bruk av enum eller int i 'case', men også områder, strenger eller objekttyper. Må inneholde alle muligheter eller ha et uttrykk. Dekk deretter alle UserError-verdier.
Når du bruker visning? .showEmptyNameError () (med et spørsmålstegn etter visningen), beskytter vi oss mot NullPointer Visning kan overstyres i metode onDestroy , og med denne konstruksjonen vil ingenting skje.
Når en brukermodell ikke har noen feil, forteller den UserStore lagre den og be View om å vise suksess og vise detaljer.
Som nevnt ovenfor må vi implementere noen viktige ting:
interface UserDetailsPresenter: Presenter { var user: User? }
Deretter UserDetailsPresenter. Den skal ha en brukeregenskap:
class UserDetailsPresenterImpl(override var view: UserDetailsView?): UserDetailsPresenter { override var user: User? = null set(value) { field = value if(field != null){ view?.showUserDetails(field!!) } else { view?.showNoUserError() } } }
Dette grensesnittet vil bli implementert i UserDetailsPresenterImpl . Du må overskrive brukerens eiendom. Hver gang denne egenskapen tildeles, må brukeren oppdateres i visningen. Vi kan bruke en setter eiendom for dette:
class UserDetailsActivity: AppCompatActivity(), UserDetailsView { private val presenter: UserDetailsPresenter by lazy { UserDetailsPresenterImpl(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_user_details) val user = intent.getParcelableExtra(USER_KEY) presenter.user = user } override fun showUserDetails(user: User) { userFullName.text = '${user.name} ${user.surname}' } override fun showNoUserError() { toast(R.string.no_user_error) finish() } override fun onDestroy() { presenter.onDestroy() } }
Implementeringen UserDetailsView , UserDetailsActivity , Det er veldig enkelt. Som før har vi et presentatørobjekt opprettet ved lat lasting. Brukeren under visning må passeres av intensjon. Det er et lite problem med dette for nå, og vi vil løse det om et øyeblikk. Når vi har intensjonsbrukeren, må View tilordne den til presentatøren. Etter det blir brukeren oppdatert på skjermen, eller hvis den er null, vises feilen (og aktiviteten avsluttes, men programlederen vet ikke):
anular divertido showUserDetails(usuario: Usuario) { startActivity(USER_KEY to user) /* extensión anko – empieza UserDetailsActivity y pasa el usuario a USER_KEY in intent */ }
Å sende objekter gjennom hensikter krever at dette objektet implementerer det parsible grensesnittet. Dette er veldig 'skittent' arbeid. Personlig hater jeg å gjøre dette på grunn av alle skapere, eiendommer, besparelser, restaurering og så videre. Heldigvis er det en plugg inn egnet, pakke for Kotlin. Etter å ha installert den, kan vi generere pakken med bare ett klikk.
Det siste vi trenger å gjøre er å implementere showUserDetails (bruker: bruker) i hovedaktiviteten vår:
|_+_|
Og det er det.
Vi har en enkel app som lagrer en bruker (faktisk ikke lagret, men vi kan legge til denne funksjonaliteten uten å berøre presentatøren eller visningen) og presentere den på skjermen. I fremtiden, hvis vi vil endre måten brukeren blir presentert på skjermen, for eksempel: to aktiviteter til to fragmenter i en aktivitet, eller to tilpassede visninger; endringer vil bare bli sett i Vis klasser. Selvfølgelig, hvis vi ikke endrer funksjonaliteten eller strukturen til modellen. Presentatøren, som ikke vet nøyaktig hva View er, trenger ikke noen endringer.
Har du problemer med utviklingen av Android-applikasjonene dine? Sjekk ut disse optimaliseringstipsene og teknikkene.I applikasjonen vår blir Presenter opprettet hver gang en aktivitet opprettes. Denne tilnærmingen, eller den motsatte, hvis presentator skal fortsette gjennom forekomster av aktivitet, er et tema for mye diskusjon over Internett. For meg avhenger det av applikasjonen, dens behov og utvikleren. Noen ganger er det bedre å ødelegge programlederen, noen ganger ikke. Hvis du bestemmer deg for å fortsette en, er en veldig interessant teknikk å bruke LoaderManager For det.
Som nevnt ovenfor må MVP være en del av Onkel Bobs rene arkitektur . På den annen side bør gode utviklere bruke Dolk å injisere avhengighet av presentatører i aktiviteter. Det hjelper også å vedlikeholde, teste og bruke koden din i fremtiden. For tiden fungerer Kotlin veldig bra med Dagger (før den offisielle utgivelsen var det ikke så lett) og også med andre nyttige Android-biblioteker.
For meg er Kotlin et flott språk. Det er moderne, klart og uttrykksfullt, mens det fremdeles utvikles av flotte mennesker. Og vi kan bruke hvilken som helst ny versjon på hvilken som helst Android-enhet og versjon. Hva som gjør meg sint på Java, gjør Kotlin det bedre.
Selvfølgelig er som sagt ingenting ideelt. Kotlin har også noen ulemper. Nyere versjoner av Gradle-plugins (hovedsakelig alfa eller beta) fungerer ikke bra med dette språket. Mange klager over at byggetiden er litt lengre enn ren Java, og apk-ene har noen ekstra MB-er. Likevel, Android Studio Y Gradle De blir stadig bedre, og telefoner får mer og mer plass til apper. Dette er grunnen til at jeg tror Kotlin kan være et veldig hyggelig språk for alle Android-utviklere. Bare prøv og del i kommentarfeltet nedenfor hva du synes.
Kildekoden for eksempelprogrammet er tilgjengelig på Github .