Lärm: Kuidas teha CRUDi Firebase RTDB-ga

Sissejuhatus

Eelmises postituses Flutter: Kuidas Firebase abil kasutajat sisse logida, rääkisime sellest, kuidas rakendada kasutajate sisselogimist või registreeruda ekraanil Firebase autentimisega. Sama projekti abil hakkame selles postituses tutvustama CRUD-i või looma, lugeda, värskendada ja kustutada toiminguid Firebase RTDB või reaalajas andmebaasiga.

Alustamine

Selle projekti jaoks peate projekti registreerima Firebase'is ja lisama oma projekti allalaaditud konfiguratsioonifaili. Vajalikud toimingud leiate eelmises postituses mainitud kohta. See samm on vajalik ainult siis, kui eelistate oma Firebase'i andmebaasi häälestada, vastasel juhul võite kaevandust kasutada koos konfiguratsioonifailiga, mille olen ka githubi projekti lisanud. Kas leiate selle postituse allosas projekti lingi.

1. samm: looge mudeliklass

Nii et tagasi sinna, kuhu me varem oleme jäänud, õnnestus meil kuvada tervitussõnum pärast seda, kui kasutaja on oma kontole edukalt sisse loginud. Seda kuvatakse avalehel home_page.dart. Meie ülesanderakenduse lihtsuse huvides salvestame lihtsalt ülesande nime ja võimaldame kasutajal märkida, et see on lõpetatud või mitte. Iga ülesandeüksuse teabe salvestamiseks peab meil olema mudeliklass. Ülesande näidisklass näeks välja järgmine:

/mudelid/todo.dart

klass Todo {
  Keel võti;
  Keelteema;
  bool valmis;
  String userId;

  Todo (see objekt, see.kasutajaId, seetekst lõpule viidud);

  Todo.fromSnapshot (DataSnapshoti hetktõmmis):
    võti = hetktõmmis.võti,
    userId = snapshot.value ["userId"],
    subjekt = snapshot.value ["subjekt"],
    valmis = snapshot.value ["täidetud"];

  toJson () {
    tagastama {
      "userId": userId,
      "subjekt": subjekt,
      "lõpetatud": täidetud,
    };
  }
}

Iga ülesandeülesanne on ainulaadne ja sellel on oma võti. Igal üksusel on nimi või teema, lipp, et jälgida selle valmimist või lõpetamist ning selle kasutaja loonud ID. Uue ülesande loomiseks on vajalikud kõik parameetrid, välja arvatud võti, edastamiseks konstruktorisse Todo (). Võtme genereerib RTDB automaatselt ja salvestatakse uue ülesande lisamisel.

Kui andmed tuuakse Firebase RTDB-st, on need json-vormingus. Seega on meil Todo.fromSnapshot (DataSnapshoti hetktõmmis) võimaldab meil kaardistada andmed jsoni vormingust Todo vormingusse. ToJson () teeb vastupidist, kaardistades andmed uuesti jsoni vormingusse enne, kui me need üles laadime Firebase RTDB-sse.

2. samm: lähtestage päring

Koostasime oma home_page.dart tagasi todode loendi, kasutades nimekirja _todoList = new List (). Kui Firebase'ist tõmmatakse todode loend, salvestame selle kohalike loendimuutujate hulka.

Kasutame lõplikku FirebaseDatabase _database = FirebaseDatabase.instance; et pääseda juurde Firebase eksemplarile. Seejärel ehitame sellelt eksemplarilt päringu, kasutades:

Päring _todoQuery = _ andmebaas
    .reference ()
    .child ("todo")
    .orderByChild ("userId")
    .equalTo (vidin.kasutaja ID);

Selles päringus, kasutades FirebaseDatabase eksemplari, hangime viite kõigile andmetele tee / ülesande all olevatele andmetele. Kui teil on teistsugune ülesannete tase, siis on teie päringuks _database.reference (). Child ("todo"). Child ("other level"). Nii .orderByChild ("xx xx") kui ka .equalTo ("xx xx") on see, mida ma ütlen Firebase'ile. Soovin nimekirja tododest, kus iga todo's userId on see, mille ma teile annan. Kõlab loogiliselt?

Kuidas see RTDB-s välja näeb:

3. samm: kuulajate seadistamine

Kasutades just ülaltoodud päringut, lisame sellele 2 tüüpi voo tellimusi. Üks on onChildAdded ja teine ​​onChildChanged. OnChildAdded.listen () teeb seda, kas ta kuulab kõiki uusi Firebase'i lisatud todo-üksusi ning võtab vastu sündmuse ja suunab tagasihelistamise funktsiooni, mis antud juhul on _onEntryAdded. Sama kehtib ka saidil onChildChanged.listen (), mis kuulab Firebase'i andmete mis tahes muudatusi, näiteks märkige üksus todo valmis.

_onTodoAddedSubscription = _todoQuery.onChildAdded.listen (_onEntryAdded);
_onTodoChangedSubscription = _todoQuery.onChildChanged.listen (_onEntryChanged);

Mis on funktsiooni _onEntryAdded funktsioon? See püüab sündmuse hetktõmmise ja teisendab jsonist todo mudeli vormingusse ja lisab todode loendisse.

_onEntryAdded (sündmuse sündmus) {
  setState (() {
    _todoList.add (Todo.fromSnapshot (event.snapshot));
  });
}

Funktsiooni _onEntryChanged jaoks hangib ta võtme sündmuse hetktõmmist ja hankib indeksi todo loendist. Seejärel värskendab see loendi indeksist seda konkreetset ülesannet sündmuse hetktõmmisega.

_onEntryChanged (sündmuse sündmus) {
  var oldEntry = _todoList.singleWhere ((kirje) {
    return entry.key == event.snapshot.key;
  });

  setState (() {
    _todoList [_todoList.indexOf (oldEntry)] = Todo.fromSnapshot (event.snapshot);
  });
}

StreamSubscripti tellimuse nõuetekohaseks tühistamiseks kasutame dispose () meetodi sees lihtsalt .cancel ()

@ ületamine
tühista käsutamine () {
  _onTodoAddedSubscription.cancel ();
  _onTodoChangedSubscription.cancel ();
  super.dispose ();
}

4. samm: looge see loeteluvaade

Mulle meeldib kasutada ListView, kui on vaja dünaamiliselt muutuva üksuste loendi iteratsiooniks ja loendis kuvamiseks. Niisiis hakkame itereerima kõiki _todoListis sisalduvaid todo üksusi. ListView võtab sisse üksuseCount, mis on lihtsalt todo-loendi suurus, st _todoList.count. ListView võtab sisse ka üksuse itemBuilder, mis on osa, mis ehitab ühe paani ühe ülesandeüksuse kuvamiseks. Üksiku ülesandeüksuse kuvamiseks hakkame kasutama vidinat ListTile. ListTile aktsepteerib mõningaid parameetreid, näiteks ikooni või muu vidina paigutamise lõpptähtaega ListTile'i paremale küljele, pealkirja ja subtiitrit 2 erinevas kontekstis ja suuruses kuvatava teksti jaoks, mis viivad sarnaselt lõppu, kuid ListTile'i vasakule küljele jt.

Igal ListTile-l kuvame halli linnukese, kui ülesanne pole lõpule viidud, ja rohelise linnukesega, kui ülesanne on lõpetatud. Selleks saame kasutada kolmepoolset operaatorit, mis on? , mis on sarnane juhul, kui oleks muu väitega.

Selle kasutamiseks pakume teatud tingimuste kontrollimise lolliks (antud juhul on Firebase'is üksuse täidetud lipu kontrollimine) ja lõpetame sellega?

(_todoList [register] .täielik)? [Tehke midagi, kui see on lõpule viidud]: [Tehke midagi, kui pole lõpule viidud]

Seega näeb meie ListTile välja selline:

laps: ListTile (
  pealkiri: Tekst (
    teema,
    stiil: TextStyle (fontSize: 20.0),
  ),
  lõpp: IconButton (
      ikoon: (_todoList [register]. valmis)
          ? Ikoon (
        Icons.done_outline,
        värv: värvid.green,
        suurus: 20,0,
      )
          : Ikoon (ikoonid.done, värv: Colors.grey, suurus: 20,0),
      onPressed: () {
        _updateTodo (_todoList [register]);
      }),
)

Ja üldine ListView:

Vidin _showTodoList () {
  if (_todoList.length> 0) {
    tagasi ListView.builder (
        shrinkWrap: tõsi,
        itemCount: _todoList.length,
        itemBuilder: (BuildContext kontekst, int indeks) {
          String todoId = _todoList [register] .key;
          Stringi teema = _todoList [register] .subjekt;
          bool valmis = _todoList [register] .täielik;
          String userId = _todoList [register] .userId;
          tagastamine keelatud (
            võti: võti (todoId),
            taust: konteiner (värv: Colors.red),
            onDismissed: (suund) async {
              _deleteTodo (todoId, indeks);
            },
            laps: ListTile (
              pealkiri: Tekst (
                teema,
                stiil: TextStyle (fontSize: 20.0),
              ),
              lõpp: IconButton (
                  ikoon: (valmis)
                      ? Ikoon (
                    Icons.done_outline,
                    värv: värvid.green,
                    suurus: 20,0,
                  )
                      : Ikoon (ikoonid.done, värv: Colors.grey, suurus: 20,0),
                  onPressed: () {
                    _updateTodo (_todoList [register]);
                  }),
            ),
          );
        });
  } veel {
    tagastamise keskus (laps: tekst ("Tere tulemast. Teie nimekiri on tühi"),
      textAlign: TextAlign.center,
      stiil: TextStyle (fontSize: 30.0),));
  }
}

Pange tähele, et ListTile on ümbritsetud teise vidinakõnega Keelatud. See on vidin, mis võimaldab kasutajal pühkida kogu ListTile'i, et jäljendada kustutamistoimingut.

Samm 5: vapustav FAB

Jätkates endiselt kodu_lehekülge.darti, ehitamismeetodil, mis tagastab tellingu, allpool, loome FAB-i või hõljuva toimingunupu. Selle nupu eesmärk on lubada kasutajal lisada loendisse uusi ülesandeid. FAB kuvab hoiatuste dialoogi, mis sisaldab tekstivälja, mille abil kasutaja saab sisestada uue ülesande nime.

floatingActionButton: ujuvActionButton (
  onPressed: () {
    _showDialog (kontekst);
  },
  tööriistavihje: 'suurendamine',
  laps: ikoon (Icons.add),
)

Hoiatuste dialoogi kuvamiseks ei saa te lihtsalt AlertDialogi tagastada ja oodata, et see kuvatakse. Selle asemel peame kasutama oodata showDialog () ja tagastama AlertDialog selle ehitaja sees. AlertDialog sisaldab tekstivälja, mille väärtust hoiab textEditingController koos kahe salvestamise ja tühistamise nupuga. Nupp Salvesta saab ilmselgelt uue ülesandeüksuse nime ja loob enne Firebase üleslaadimist uue ülesandekogu.

_showDialog (BuildContext kontekst) async {
  _textEditingController.clear ();
  oota showDialog  (
      kontekst: kontekst,
      ehitaja: (BuildContext kontekst) {
        tagasta AlertDialog (
          sisu: uus rida (
            lapsed:  [
              uus laiendatud (
                  laps: uus tekstväli (
                kontroller: _textEditingController,
                autofookus: tõsi,
                teenetemärk: uus InputDecoration (
                  labelText: 'Lisa uus ülesanne',
                ),
              ))
            ],
          ),
          toimingud:  [
            uus FlatButton (
                laps: const Tekst ('Tühista'),
                onPressed: () {
                  Navigator.pop (kontekst);
                }),
            uus FlatButton (
                laps: const Tekst ('Salvesta'),
                onPressed: () {
                  _addNewTodo (_textEditingController.text.toString ());
                  Navigator.pop (kontekst);
                })
          ],
        );
      });
}

Samm 5: olgem CRUD

Looge

Uue ülesandeüksuse loomiseks võtame kasutaja sisestatud nime AlertDialogi TextFieldi väljal, kui nad koputavad nupule FloatingActionButton. Kohendame uue ülesandeobjekti nime sisestamisega. Lõpuks laadime Firebase'i üles faili _database.reference (). Laps (“todo”). Push (). Set (todo.toJson ())

_addNewTodo (string todoItem) {
  if (todoItem.length> 0) {
    Todo todo = new Todo (todoItem.toString (), widget.userId, false);
    _database.reference (). laps ("todo"). push (). set (todo.toJson ());
  }
}

Loe

Lugemiseks on eespool mainitud, et peate looma päringu, mis on:

_todoQuery = _ andmebaas
    .reference ()
    .child ("todo")
    .orderByChild ("userId")
    .equalTo (vidin.kasutaja ID);

Päringust kinnitame 2 kuulajat, mis on onChildAdded ja onChildChanged ning käivitavad iga vastava tagasihelistamismeetodi koos sündmuse hetktõmmistega. Sündmuse hetkepildist teisendame need lihtsalt todo-klassiks ja lisame loendisse

_onEntryAdded (sündmuse sündmus) {
  setState (() {
    _todoList.add (Todo.fromSnapshot (event.snapshot));
  });
}
_onEntryChanged (sündmuse sündmus) {
  var oldEntry = _todoList.singleWhere ((kirje) {
    return entry.key == event.snapshot.key;
  });

  setState (() {
    _todoList [_todoList.indexOf (oldEntry)] =
        Todo.fromSnapshot (sündmus.snapshot);
  });
}

Kasutaja ID-l põhinevate päringute paremaks muutmiseks on soovitatav Firebase RTDB reeglitesse seada reegel. See on kõnede indekseerimine ja aitab Firebase'il teie andmete paigutust optimeerida, parandades reageerimise aega. Lisateavet leiate jaotisest Oma andmete indekseerimine Firebase'i kaudu.

{
  / * Turvareeglite kohta lisateabe saamiseks külastage lehte https://firebase.google.com/docs/database/security. * /
  "reeglid": {
    "tegema": {
      ".indexOn": "userId",
    },
    ".read": tõsi,
    ".write": tõsi
  }
}

Uuenda

Kasutaja saab märkida iga ülesandeüksuse lõpetatuks või selle toimingu tagasi võtta. Nad saavad lihtsalt koputada iga todoListTile paremal küljel olevale linnukeseikoonile. Värskenduse jaoks peame hankima todo.key, kuna meil on vaja juurde pääseda teele / todo / todo-unikaalne-võti, et saaksime värskendada seda, mis sellel teel on. Meetod sarnaneb Looga selles mõttes, et ta kasutab .set (), kuid erinevus seisneb .childi (todo.key) lisamises teele.

_updateTodo (Todo todo) {
  // Lülita lõpule
  todo.completed =! todo.completed;
  if (todo! = null) {
    _database.reference (). laps ("todo"). laps (todo.key) .set (todo.toJson ());
  }
}

Kustuta

Üksuse kustutamine Firebase'ist on lihtne. Sarnaselt värskendusega peame hankima õige todo.key, kuid kasutame meetodit .remove ().

Pange tähele, et erinevalt lisatud või muudetud üksuse kuulajast pole üksuse eemaldamiseks ühtegi kuulajat. Seega ei saa kuidagi neid 2 kuulaja meetodit käivitada ja andmebaasist uusimat ülevaadet saada. Selleks peame üksuse käsitsi oma kohalikust muutujast _todoList eemaldama ainult siis, kui kustutamine Firebase'ist on edukas.
_deleteTodo (String todoId, int index) {
  _database.reference (). laps ("todo"). laps (todoId) .remove (). seejärel ((_) {
    print ("Kustuta $ todoId õnnestus");
    setState (() {
      _todoList.removeAt (register);
    });
  });
}

Demo

Rakendus näeb välja selline

Lõpliku rakenduse demo

Github

Lähtekood on saadaval:

https://github.com/tattwei46/flutter_login_demo

Tunnustus

Täname, et leidsite aega selle postituse lugemiseks. Loodan, et see aitab teid teie imelisel teekonnal koos Flutteriga. Kui leiate, et sellest on abi, palun julgustage mind kirjutama rohkem selliseid artikleid