Opprett en vekttracker-app med Cloud Firestore

Lagring av appens data i skyen er svært viktig i disse dager, fordi brukere har en tendens til å eie flere enheter og at appene skal synkroniseres på tvers av dem alle. Med Cloud Firestore, en real-time NoSQL-database tilgjengelig på Firebase-plattformen, er det enklere og sikrere enn noen gang før.

I en tidligere opplæring, introduserte jeg deg til alle de kraftige funksjonene Cloud Firestore har å tilby. I dag skal jeg vise deg hvordan du bruker den sammen med andre Firebase-produkter, for eksempel FirebaseUI Auth og Firebase Analytics, for å lage en enkel, men høyst skalerbar, vekttracker-app.

Forutsetninger

For å følge denne trinnvise opplæringen må du:

  • den nyeste versjonen av Android Studio
  • en Firebase-konto
  • og en enhet eller emulator som kjører Android 5.0 eller høyere

1. Prosjektoppsett

For å kunne bruke Firebase-produkter i Android Studio-prosjektet ditt, trenger du Google Services Gradle-plugin, en Firebase-konfigurasjonsfil og noen få gjennomføring avhengigheter. Med Firebase Assistant kan du få dem alle veldig enkelt.

Åpne assistenten ved å gå til Verktøy> Brannbase. Deretter velger du Analytics alternativet og klikk på Logg på en Analytics-hendelse link.

Du kan nå trykke på Koble til Firebase knappen for å koble ditt Android Studio-prosjekt til et nytt Firebase-prosjekt.

Men for å faktisk legge til plugin og gjennomføring avhengigheter, må du også trykke på Legg til Analytics i appen din knapp.

Vekttracker-appen vi lager idag, skal bare ha to funksjoner: lagre vekter og vise dem som en liste sortert i omvendt kronologisk rekkefølge. Vi vil selvfølgelig bruke Firestore til å lagre vekter. For å vise dem som en liste, bruker vi imidlertid Firestore-relaterte komponenter tilgjengelig i FirebaseUI-biblioteket. Legg derfor til følgende gjennomføring avhengighet til app modulens build.gradle fil:

implementering 'com.firebaseui: firebase-ui-firestore: 3.2.2'

Brukerne må kun kunne se sine egne vekter, ikke vekter av alle som bruker appen. Derfor må vår app ha muligheten til å identifisere sine brukere unikt. FirebaseUI Auth tilbyr denne muligheten, så legg til følgende avhengighet neste:

implementering 'com.firebaseui: firebase-ui-auth: 3.2.2'

Vi vil også trenge noen Material Design widgets for å gi vår app et behagelig utseende. Så sørg for at du legger til biblioteket Design Support og Material Dialogs-biblioteket som avhengigheter.

implementering 'com.android.support:design:26.1.0' implementering 'com.afollestad.material-dialoger: kjerne: 0.9.6.0'

Til slutt trykker du på Synkroniser nå knappen for å oppdatere prosjektet.

2. Konfigurere Firebase Authentication

Firebase Authentication støtter en rekke identitetsleverandører. Men alle er deaktivert som standard. For å aktivere en eller flere av dem, må du besøke Firebase-konsollen.

I konsollen velger du Firebase-prosjektet du opprettet i forrige trinn, gå til det Godkjenning delen, og trykk på Sett inn påloggingsmetode knapp.

For å tillate brukere å logge inn på vår app ved hjelp av en Google-konto, aktiverer du Google som leverandør, gi et meningsfylt publikumsnavnet til prosjektet, og trykk på Lagre knapp.

Google er den enkleste identitetsleverandøren du kan bruke. Det trenger ingen konfigurasjon, og Android Studio-prosjektet ditt trenger ikke flere avhengigheter for det.

3. Konfigurere Cloud Firestore

Du må aktivere Firestore i Firebase-konsollen før du begynner å bruke den. For å gjøre det, gå til database delen og trykk på Kom i gang knapp tilstede i Cloud Firestore Beta kort.

Du blir nå bedt om å velge en sikkerhetsmodus for databasen. Pass på at du velger Start i låst modus alternativet og trykk på Aktiver knapp.

I låst modus, som standard, vil ingen kunne få tilgang til eller endre innholdet i databasen. Derfor må du nå opprette en sikkerhetsregel som tillater brukere å lese og skrive kun de dokumentene som tilhører dem. Begynn med å åpne regler tab.

Før vi oppretter en sikkerhetsregel for databasen, må vi sluttføre hvordan vi skal lagre data i den. Så la oss si at vi skal ha en toppnivå samling kalt brukere inneholder dokumenter som representerer våre brukere. Dokumentene kan ha unike IDer som er identiske med IDene som Firebase Authentication-tjenesten genererer for brukerne.

Fordi brukerne vil legge til flere vektoppføringer i dokumentene sine, er det ideelt å bruke en undersamling for å lagre disse oppføringene. La oss ringe til undersamlingen vekter.

Basert på ovenstående skjema kan vi nå lage en regel for banen brukerne / user_id / vekter vekt /. Regelen vil være at en bruker har lov til å lese fra og skrive til banen bare hvis bruker-ID variabel er lik brukerens Firebase Authentication ID.

Oppdatere innholdet i regnskapsredigeren.

service cloud.firestore match / databases / database / documents match / users / user_id / weight / weight tillate lese, skrive: hvis user_id == request.auth.uid; 

Til slutt trykker du på publisere knappen for å aktivere regelen.

4. Godkjenne brukere

Vår app må kun brukes hvis brukeren er logget på den ved hjelp av en Google-konto. Derfor, så snart den åpnes, må den kontrollere om brukeren har en gyldig Firebase Authentication ID. Hvis brukeren har ID, bør den gå videre og gjengi brukergrensesnittet. Ellers skal det vise en påloggingsskjerm.

For å sjekke om brukeren har en ID, kan vi bare sjekke at nåværende bruker eiendom av FirebaseAuth klassen er ikke null. Hvis det er null, kan vi opprette en påloggingsavtale ved å ringe createSignInIntentBuilder () metode av AuthUI klasse.

Følgende kode viser hvordan du gjør det for Google som identitetsleverandør:

hvis (FirebaseAuth.getInstance (). currentUser == null) // Logg inn startActivityForResult (AuthUI.getInstance (). createSignInIntentBuilder () .setAvailableProviders (arrayListOf (AuthUI.IdpConfig.GoogleBuilder () .building ()). ), 1) else // Allerede logget på showUI ()

Legg merke til at vi ringer en metode som heter showUI () hvis en gyldig ID allerede er tilstede. Denne metoden eksisterer ikke ennå, så opprett den og la kroppen være tom for nå.

privat morsomt showUI () // å gjøre

For å fange resultatet av innloggingsintensjonen må vi overstyre onActivityResult () metode for aktiviteten. Inne i metoden, hvis verdien av resultCode argumentet er RESULT_OK og nåværende bruker Egenskapen er ikke lenger null, det betyr at brukeren klarte å logge inn med hell. I dette tilfellet må vi igjen ringe til showUI () metode for å gjengi brukergrensesnittet.

Hvis brukeren ikke logger på, kan vi vise en ristet brød og lukke appen ved å ringe bli ferdig() metode.

Følg deretter følgende kode til aktiviteten:

overstyr moro onActivityResult (requestCode: Int, resultCode: Int, data: Intent?) super.onActivityResult (requestCode, resultCode, data) hvis (requestCode == 1) if (resultCode == Aktivitet.RESULT_OK && FirebaseAuth.getInstance .currentUser! = null) // Vellykket logget på showUI () else // Logg inn mislyktes Toast.makeText (dette, "Du må logge inn for å fortsette", Toast.LENGTH_LONG) .show () finish () 

På dette tidspunktet, hvis du kjører appen for første gang, bør du kunne se en påloggingsskjerm som ser slik ut:

På etterfølgende løp - takket være Google Smart Lock, som er aktivert som standard - blir du automatisk logget på.

5. Definere layouter

Vår app trenger to layouter: en for hovedaktiviteten og en for vektinngangene som vil bli vist som elementer i den omvendt kronologisk bestilte listen.

Oppsettet av hovedaktiviteten må ha en RecyclerView widget, som vil fungere som listen, og a FloatingActionButton widget, som brukeren kan trykke for å opprette en ny vektoppføring. Etter å ha plassert dem begge inne i a RelativeLayout Widget, din aktivitets layout XML-fil skal se slik ut:

     

Vi har tilknyttet en hendelseshåndterer på stedet som heter addWeight () med FloatingActionButton widget. Handleren eksisterer ikke ennå, så skape en stub for den inne i aktiviteten.

morsomt addWeight (v: View) // å gjøre

For å holde opplegget til vektoppføringen enkel, skal vi bare ha to TextView widgets inne i den: en for å vise vekten og den andre for å vise tidspunktet hvor oppføringen ble opprettet. Bruker en LinearLayout widget som en beholder for dem vil være tilstrekkelig.

Opprett følgelig en ny layout XML-fil weight_entry.xml og legg til følgende kode for det:

    

6. Opprette en modell

I det forrige trinnet så du at hver vektinngang har en vekt og tid forbundet med den. For å la Firestore vite om dette, må vi lage en modell for vektinngangen.

Firestore-modeller er vanligvis enkle dataklasser med de nødvendige medlemsvariablene.

dataklasse WeightEntry (varvekt: Dobbel = 0,0, var tidsstempel: Lang = 0)

Nå er det også en god tid å lage en visningsholder for hver vektinngang. Visningsholderen, som du kanskje har gjettet, vil bli brukt av RecyclerView widget for å gjengi listepostene. Så opprett en ny klasse som heter WeightEntryVH, som strekker seg RecyclerView.ViewHolder klasse, og opprett medlemsvariabler for begge TextView widgets. Ikke glem å initialisere dem ved hjelp av findViewById () metode. Følgende kode viser deg hvordan du gjør det kortfattet:

klasse WeightEntryVH (itemView: View?): RecyclerView.ViewHolder (itemView) var weightView: TextView? = itemView? .findViewById (R.id.weight_view) var timeView: TextView? = itemView? .findViewById (R.id.time_view)

7. Opprette unike brukerdokumenter

Når en bruker prøver å opprette en vektoppføring for første gang, må vår app opprette et eget dokument for brukeren inne i brukere samling på Firestore. Som vi bestemte oss tidligere, vil ID-en for dokumentet være noe annet enn brukerens Firebase Authentication ID, som kan fås ved hjelp av uid eiendom av nåværende bruker gjenstand.

For å få en referanse til brukere samling, må vi bruke samling() metode av FirebaseFirestore klasse. Vi kan da ringe det dokument() metode og passere uid som et argument for å opprette brukerens dokument.

Vi må ha tilgang til de brukerspesifikke dokumentene, både når du leser og lager viktige oppføringer. For å unngå koding av logikken ovenfor, foreslår jeg at du oppretter en egen metode for den.

Private Fun GetUserDocument (): DocumentReference val db = FirebaseFirestore.getInstance () val brukere = db.collection ("brukere") val uid = FirebaseAuth.getInstance (). currentUser !!

Merk at dokumentet vil bli opprettet bare én gang per bruker. Med andre ord, vil flere samtaler til den ovennevnte metoden alltid returnere det samme dokumentet, så lenge brukeren bruker den samme Google-kontoen.

8. Legge til vektinnlegg

Når brukerne trykker på flytende handlingsknappen i appen vår, må de kunne opprette nye viktige oppføringer. For å la dem skrive inn sine vekter, la oss nå opprette en dialog som inneholder en EditText widget. Med Material Dialog-biblioteket er det ekstremt intuitivt.

Inne i addWeight () metode, som fungerer som hendelseshåndterer på klikkknappen, oppretter en MaterialDialog.Builder eksempel og ring det tittel() og innhold() metoder for å gi dialogen din en tittel og en meningsfull melding. På samme måte, ring input () metode og pass TYPE_CLASS_NUMBER som et argument for det for å sikre at brukeren bare kan skrive inn tall i dialogboksen.

Neste, ring på inngang () Metode for å spesifisere et hint og knytte en hendelseshåndterer til dialogboksen. Handleren vil motta vekten brukeren skrev inn som et argument.

Til slutt, sørg for at du ringer til vise fram() metode for å vise dialogboksen.

MaterialDialog.Builder (this) .title ("Legg vekt") .content ("Hva er vekten din idag?") .InputType (InputType.TYPE_CLASS_NUMBER eller InputType.TYPE_NUMBER_FLAG_DECIMAL) .inngang ("vekt i pounds", " _, vekt -> // For å gjøre) .show ()

Inne i hendelsesbehandleren må vi nå legge til kode for å faktisk opprette og fylle ut et nytt vektoppføringsdokument. Fordi dokumentet må tilhøre vekter samling av brukerens unike dokument, for å få tilgang til samlingen må du ringe samling() Metode for dokumentet som returneres av getUserDocument () metode.

Når du har samlingen, kan du ringe den Legg til() metode og passere en ny forekomst av WeightEntry klasse til det for å lagre oppføringen.

getUserDocument () .collection ("weight") .add (WeightEntry (weight.toString (). toDouble (), Date () .tid))

I ovennevnte kode kan du se at vi bruker tid eiendom av Dato klasse for å knytte en tidsstempel med posten.

Hvis du kjører appen nå, bør du kunne legge til nye vektoppføringer til Firestore. Du vil ikke se dem i appen ennå, men de vil være synlige i Firebase-konsollen.

9. Vise Vektoppføringene

Det er nå på tide å fylle RecyclerView widget av vårt layout. Så start med å lage en referanse for det ved å bruke findViewById () metode og tilordne en ny forekomst av LinearLayoutManager klasse til den. Dette må gjøres inne i showUI () metode vi opprettet tidligere.

valvekterView = findViewById(R.id.weights) weightsView.layoutManager = LinearLayoutManager (dette)

De RecyclerView Widget må vise alle dokumentene som er til stede i vekter samling av brukerens dokument. Videre skal de nyeste dokumentene vises først. For å oppfylle disse kravene må vi nå opprette en forespørsel ved å ringe samling() og rekkefølge etter() fremgangsmåter.

For effektivitets skyld kan du begrense antall verdier som returneres av spørringen ved å ringe grense() metode.

Følgende kode oppretter en forespørsel som returnerer de 90 siste viktige oppføringene som er opprettet av brukeren:

val query = getUserDocument (). samling ("vekter") .orderBy ("tidsstempel", Query.Direction.DESCENDING) .limit (90)

Ved hjelp av spørringen må vi nå opprette en FirestoreRecyclerOptions objekt, som vi skal bruke senere til å konfigurere adapteren til vår RecyclerView widget. Når du passerer spørsmål eksempel på setQuery () Metoden til byggmesteren, sørg for at du spesifiserer at resultatene som returneres er i form av WeightEntry objekter. Følgende kode viser hvordan du gjør det:

val alternativer = FirestoreRecyclerOptions.Builder() .setQuery (spørring, WeightEntry :: class.java) .setLifecycleOwner (this) .build ()

Du har kanskje lagt merke til at vi gjør vår nåværende aktivitet til livscykelinnehaveren av FirestoreRecyclerOptions gjenstand. Å gjøre dette er viktig fordi vi vil at adapteren vår skal reagere hensiktsmessig på vanlige livssyklushendelser, for eksempel at brukeren åpner eller lukker appen.

På dette tidspunktet kan vi lage en FirestoreRecyclerAdapter objekt, som bruker FirestoreRecyclerOptions motsette seg å konfigurere seg selv. Fordi det FirestoreRecyclerAdapter klassen er abstrakt, skal Android Studio automatisk overstyre sine metoder for å generere kode som ser slik ut:

val adapter = objekt: FirestoreRecyclerAdapter(valg) overstyr moro onBindViewHolder (holder: WeightEntryVH, posisjon: Int, modell: WeightEntry) // Å gjøre overstyr moro påCreateViewHolder (foreldre: ViewGroup ?, viewType: Int): WeightEntryVH // Å gjøre

Som du kan se, er FirestoreRecyclerAdapter klassen er veldig lik den RecyclerView.Adapter klasse. Faktisk er det avledet av det. Det betyr at du kan bruke den på samme måte som du vil bruke RecyclerView.Adapter klasse.

Inne i onCreateViewHolder () Metoden, alt du trenger å gjøre er å oppblåse weight_entry.xml layoutfil og returnere a WeightEntryVH se holderobjekt basert på den.

val layout = layoutInflater.inflate (R.layout.weight_entry, null) returnerer WeightEntryVH (layout)

Og inne i onBindViewHolder () metode må du bruke modell argument for å oppdatere innholdet i TextView widgets som er til stede inne i visningsholderen.

Mens du oppdaterer weightView Widget er grei, oppdaterer Timeview Widget er litt komplisert fordi vi ikke vil vise tidsstempelet, som er i millisekunder, til brukeren direkte.

Den enkleste måten å konvertere tidsstempel til en lesbar dato og klokkeslett er å bruke formatDateTime () metode av DateUtils klasse. I tillegg til tidsstempelet kan metoden akseptere flere forskjellige flagg, som den vil bruke til å formatere dato og klokkeslett. Du kan bruke flagg som passer til dine preferanser.

// Vis vektholder.weightView? .Text = "$ model.weight lb" // Vis dato og klokkeslett valformattedDate = DateUtils.formatDateTime (applicationContext, model.timestamp, DateUtils.FORMAT_SHOW_DATE eller DateUtils.FORMAT_SHOW_TIME eller DateUtils.FORMAT_SHOW_YEAR ) holder.timeView? .text = "På $ formattedDate"

Til slutt, ikke glem å peke på RecyclerView widget til adapteren vi nettopp har opprettet.

veierView.adapter = adapter

Appen er klar. Du bør nå kunne legge til nye oppføringer og se dem vises i listen nesten umiddelbart. Hvis du kjører appen på en annen enhet som har samme Google-konto, vil du se at samme vektoppføringer vises på den også.

Konklusjon

I denne opplæringen så du hvor raskt og enkelt det er å lage en fullt funksjonell vekttracker-app for Android ved hjelp av Cloud Firestore som en database. Du er velkommen til å legge til mer funksjonalitet til det! Jeg foreslår også at du prøver å publisere den på Google Play. Med Firebase Spark-planen, som for øyeblikket tilbyr 1 GB datalagring gratis, har du ingen problemer med å betjene minst et par tusen brukere.

Og mens du er her, sjekk ut noen av våre andre innlegg om Android app utvikling!