Çırpınma: Firebase RTDB ilə CRUD necə ediləcək

giriş

Flutter-in əvvəlki yazısında Firebase ilə necə giriş etməli: İstifadəçi girişinin və ya Firebase identifikasiyası ilə giriş ekranının necə tətbiq ediləcəyi barədə danışdıq. Bu yazıda eyni layihə ilə CRUD təqdim edəcəyik və ya Firebase RTDB və ya real-time verilənlər bazası ilə əməliyyatlar yaradacağıq, oxuyacağıq, yeniləyəcəyik və siləcəyik.

Başlamaq

Bu layihə üçün layihənizi Firebase-də qeydiyyatdan keçirməli və yüklənmiş konfiqurasiya sənədini layihənizə daxil etməlisiniz. Yuxarıdakı əvvəlki yazıda göstərilən addımları əldə edə bilərsiniz. Bu addım yalnız öz Firebase verilənlər bazanızı qurmağı seçdiyiniz təqdirdə lazımdır, əks halda github layihəsinə daxil etdiyim konfiqurasiya faylı ilə mina istifadə edə bilərsiniz. Bu yazının sonunda layihənin bağlantısını tapın.

Adım 1: model sinfi yaradın

İstifadəçi hesabına uğurla daxil olduqdan sonra xoş mesajı görə bildik. Bu home_page.dart-da göstərilir. Görülməli olduğumuz işin sadə olmasını təmin etmək üçün yalnız tapşırığın adını saxlayacağıq və istifadəçinin onu bitmiş və ya edilməmiş kimi qeyd etməsinə icazə verəcəyik. Ediləcək hər bir maddə haqqında məlumatları saxlamaq üçün bir model sinifinə ehtiyacımız var. Ediləcək bir maddə üçün bir model sinfi belə görünür:

/models/todo.dart

Sinif Todo {String açarı; Simli mövzu; Bool tamamlandı; String userId; Todo (bu.subject, this.userId, this.completed); Todo.fromSnapshot (DataSnapshot-Snapshot): key = snapshot.key, userId = snapshot.value ["userId"], subject = snapshot.value ["mövzu"], bitmiş = snapshot.value ["görülmüş"]; toJson () {return {"userId": userId, "subject": subject, "done": done,}; }}

Hər bir tapşırıq elementi unikaldır və öz açarı var. Hər bir maddənin adı və mövzusu, tamamlanmasını və ya tamamlanmasını izləmək üçün istifadə olunan bir bayrağı və həmin elementi kimin yaratdığını göstərən istifadəçi identifikatoru var. Yeni tapşırıq yaratmaq üçün düymədən başqa bütün parametrlər Todo () konstruktoruna ötürülməlidir. Yeni tapşırıqlar əlavə edildikdə açar avtomatik olaraq RTDB tərəfindən yaradılır və qeyd olunur.

Məlumat Firebase RTDB-dən alındıqda, json formatındadır. Beləliklə, məlumatları json formatından Todo formatına uyğunlaşdırmaq üçün istifadə edə biləcəyimiz Todo.fromSnapshot (DataSnapshot-Snapshot) var. ToJson () bunun əksini edir, yəni Firebase RTDB-yə yükləmədən əvvəl məlumatları yenidən json formatına uyğunlaşdırmaq üçün.

Adım 2: sorğu başladın

Home_page.dart səhifəmizə qayıt _todoList = yeni Siyahı () tapşırıqların siyahısını yaradır. Tapşırıqların siyahısı Firebase-dən alındıqda, onları yerli siyahı dəyişənlərində saxlayırıq.

Nəhayət FirebaseDatabase _database = FirebaseDatabase.instance istifadə edirik; Firebase nümunəsinə giriş əldə etmək. Sonra bu nümunədən bir sorğu yaradırıq:

Sorgu _todoQuery = _database .Referenz () .child ("todo") .orderByChild ("userId") .equalTo (widget.userId);

Bu sorğuda, yol / todo altındakı bütün məlumatlara istinad almaq üçün FirebaseDatabase nümunəsini istifadə edirik. Todada başqa bir səviyyəniz varsa, sorğunuz _database.reference (). Uşaq ("todo"). Uşaq ("başqa bir səviyyə"). Həm .orderByChild ("xx xx") həm də .equalTo ("xx xx") Firebase-ə tapşırıqların siyahısını istədiyimi söyləyirlər, hər tapşırığın İstifadəçi ID-si sizə verdiyim şeydir. Anlamlı?

RTDB-də belə görünür:

Adım 3: dinləyicini qurun

Yeni yaratdığımız sorğu ilə ona iki növ axın abunəliyi əlavə edirik. Biri onChildAdded, digəri onChildChanged. OnChildAdded.listen () Firebase-ə yeni tapşırıqların əlavə olunmasını gözləyir və bir hadisə və geri çağırma funksiyası alır, bu halda _onEntryAdded. Eyni şey Firebase-də məlumatların dəyişdirilməsini gözləyən onChildChanged.listen () üçün də tətbiq olunur, məsələn. B. Tapşırıqları bitmiş kimi qeyd etmək.

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

_OnEntryAdded funksiyası nədir? Tədbirin anlıq görüntüsünü çəkir və model formatını JSON-dan Todo-ya çevirir və Todos siyahısına əlavə edir.

_onEntryAdded (hadisə hadisəsi) {setState (() {_todoList.add (Todo.fromSnapshot (event.snapshot));}); }

_OnEntryChanged funksiyası açarı hadisənin anlıq görüntüsündən alır və tapşırıq siyahısından indeks alır. Daha sonra bu xüsusi tapşırığı siyahı indeksindən hadisə anlıq görüntüsündən yeniləyir.

_onEntryChanged (hadisə hadisəsi) {var oldEntry = _todoList.singleWhere ((giriş) {return entry.key == event.snapshot.key;}); setState (() {_todoList [_todoList.indexOf (oldEntry)] = Todo.fromSnapshot (event.snapshot);}); }

StreamSubscription abunəliyini düzgün şəkildə ləğv etmək üçün dispose () metodu daxilində .cancel () istifadə edirik.

@override void dispose of () {_onTodoAddedSubscription.cancel (); _onTodoChangedSubscription.cancel (); super.dispose (); }

EpAdım 4: bu ListView yaradın

Ölçüsü dinamik olaraq dəyişən maddələrin siyahısını təkrarlamağa və bir siyahıda göstərməyə ehtiyac olduqda ListView-dən istifadə etmək istəyirəm. Bu vəziyyətdə, _todoListdəki fərdi tapşırıq maddələrini nəzərdən keçirəcəyik. ListView, sadəcə tapşırıq siyahısının ölçüsü olan itemCount götürür; H. _TodoList.count. ListView ayrıca, bir tapşırıq elementini göstərmək üçün tək plitəni yaradan hissə olan itemBuilder-ı götürür. Tək bir tapşırıq elementini göstərmək üçün ListTile widgetından istifadə edəcəyik. ListTile, ListTile-nin sağ tərəfində nişanlar və ya digər widgetların yerləşdirilməsi üçün arxada qalma, mətni iki fərqli kontekstdə və ölçüdə göstərmək üçün başlıq və altyazı kimi bəzi parametrləri qəbul edir.

Hər bir ListTile-də tapşırıq yerinə yetirilmədiyi təqdirdə boz bir onay işarəsi və tapşırıq yerinə yetirildiyi təqdirdə yaşıl bir onay işarəsi var. Bunun üçün üçlü operatordan istifadə edə bilərik. , if-else ifadəsinə bənzəyir.

Onu istifadə etmək üçün müəyyən şərtlər daxilində bir mantıksal yoxlama aparırıq (bu halda "tamamlanmış" bayraq Firebase-dəki element üçün yoxlanılır) və ilə çıxırıq?

(_todoList [index]. tamamlandı)? [İşi bitirdikdən sonra bir şey et]: [Bitməmiş bir şey et]

Beləliklə ListTile belə görünür:

uşaq: ListTile (Başlıq: Mətn (mövzu, üslub: TextStyle (şrift ölçüsü: 20.0),), sonunda: IconButton (ikon: (_todoList [index). tamamlanmış)? Symbol (Icons.done_outline, color: Colors.green, size : 20.0,): Icon (Icons.done, color: Colors.grey, size: 20.0), onPressed: () {_updateTodo (_todoList [index]);}),)

Və ümumi ListView:

Widget _showTodoList () {if (_todoList.length> 0) {return ListView.builder (shrinkWrap: true, itemCount: _todoList.length, itemBuilder: (BuildContext context, int index) {String todoId = _todoList [index] .key ; Dize mövzu = _todoList [index] .subject; bool tamamlandı = _todoList [index] .completed; String userId = _todoList [index] .userId; qayıtmağa icazə verilmir (açar: Key (todoId), background: konteyner (color: Colors.red ), onDississed: (direction) async {_deleteTodo (todoId, index);}, child: ListTile (Title: Text (mövzu, style: TextStyle (font size: 20.0),), sonunda: IconButton (icon: (done))? Nişan (Icons.done_outline, rəng: Colors.green, Ölçü: 20.0,): İkon (Icons.done, color: Colors.grey, size: 20.0), onPressed: () {_updateTodo (_todoList [index]); }),),); }); } else {return Center (uşaq: Mətn ("Xoş gəlmisiniz. Siyahınız boşdur", textAlign: TextAlign.center, stil: TextStyle (fontSize: 30.0),)); }}

ListTile-in başqa bir widget çağırışı ilə bağlandığını unutmayın. Bu, istifadəçinin silinmə əməli təqlid etmək üçün bütün ListTile sürüşməsinə imkan verən bir vidjetdir.

Adım 5: Möhtəşəm FAB

Bir iskeli qaytaran home_page.dart yaradılması metodunda gövdənin altında bir FAB və ya üzən hərəkət düyməsini yaradırıq. Bu düymənin məqsədi istifadəçinin siyahıya yeni tapşırıqlar əlavə etməsinə imkan verməkdir. FAB, istifadəçinin yeni tapşırığın adını daxil etməsi üçün bir mətn qutusu olan bir xəbərdarlıq dialoqunu göstərir.

floatingActionButton: FloatingActionButton (onPressed: () {_showDialog (context);}, Tooltip: 'Artım', Kind: Icon (Icons.add),)

Xəbərdarlıq dialoqunun görünməsi üçün sadəcə bir xəbərdarlıq dialoqunu qaytarmaq və görünəcəyini gözləmək olmaz. Bunun əvəzinə bu builderdə show showDialog () və return AlertDialog istifadə etməliyik. AlertDialog, bir mətn sahəsi ehtiva edir, dəyəri bir TextEditingController tərəfindən 2 FlatButtons ilə qeyd və ləğv etmək üçün qeyd olunur. Saxla düyməsinə yeni tapşırıq elementinin adını alır və Firebase-ə yüklənmədən əvvəl yeni tapşırıq nümunəsi yaradır.

_showDialog (BuildContext məzmunu) async {_textEditingController.clear (); showDialog-u gözləyin (Kontekst: Kontekst, Generator: (BuildContext-Context) {return AlertDialog (məzmun: yeni sətir (uşaqlar: [yeni genişləndirilmiş (uşaq: yeni TextField (nəzarətçi: _textEditingController, autofocus: true, dekorasiya: new InputDecoration (labelText: 'Yeni todo əlavə et',),))],), tədbirlər: [yeni FlatButton (uşaq: const Mətn ('Ləğv'), onPressed: () {Navigator.pop (kontekst);}), yeni FlatButton (uşaq: const Mətn ('Saxla'), onPressed: () {_addNewTodo (_textEditingController) .text.toString ()); Navigator.pop (kontekst);})],); }); }

Adım 5: gəlin CRUD edək

Yaradın

Yeni bir tapşırıq elementi yaratmaq üçün istifadəçinin FloatingActionButton düyməsini vurduğu zaman AlertDialogdakı mətn sahəsindəki ad girişini götürürük. Ad girişi ilə yeni bir tapşırıq obyekti hazırlayırıq. Nəhayət _database.reference () ilə yükləyirik. Uşaq ("todo"). İtin (). Firebase-də (todo.toJson ()) seçin.

_addNewTodo (String todoItem) {if (todoItem.length> 0) {Todo todo = new Todo (todoItem.toString (), widget.userId, false); _database.reference (). uşaq ("todo"). bas (). set (todo.toJson ()); }}

Oxu

Oxumaq üçün yuxarıda qeyd olundu ki, aşağıdakı kimi bir sorğu qurmalısınız:

_todoQuery = _database .Referenz () .child ("todo") .orderByChild ("userId") .equalTo (widget.userId);

Sorğuya iki dinləyici (onChildAdded və onChildChanged) əlavə olunur ki, bu da hadisələrin anlıq görüntüləri ilə müvafiq geri çağırma metodlarını işə salır. Tədbirin anlıq görüntüsündən onu sadəcə bir ToDo sinfinə çeviririk və siyahıya əlavə edirik

_onEntryAdded (hadisə hadisəsi) {setState (() {_todoList.add (Todo.fromSnapshot (event.snapshot));}); }
_onEntryChanged (hadisə hadisəsi) {var oldEntry = _todoList.singleWhere ((giriş) {return entry.key == event.snapshot.key;}); setState (() {_todoList [_todoList.indexOf (oldEntry)] = Todo.fromSnapshot (event.snapshot);}); }

Sorğunu istifadəçi identifikatoruna əsaslanaraq yaxşılaşdırmaq üçün Firebase RTDB qaydalarına bir qayda qoymağınız tövsiyə olunur. Bu zəng indeksləşdirmədir və Firebase-ə məlumatlarınızı düzəltməyə və cavab müddətini yaxşılaşdırmağa kömək edir. Daha çox məlumat üçün Firebase-də məlumatlarınızı indeksləşdirməyə baxın.

{/ * Təhlükəsizlik qaydaları haqqında əlavə məlumat https://firebase.google.com/docs/database/security saytında mövcuddur. * / "Qaydalar": {"make": {".indexOn": "userId",}, ".read": true, ".write": true}}

Yeniləyin

İstifadəçi ediləcək hər hansı bir elementi bitmiş kimi qeyd edə bilər və ya bu addımı geri qaytara bilər. Hər bir todoListTile-in sağındakı onay işarəsi işarəsinə vurmaq olar. Yeniləmə üçün todo.keyə ehtiyacımız var, çünki bu yolun məzmununu yeniləyə bilmək üçün / todo / todo-unique-key yoluna girməliyik. Metod .set () istifadə etdiyi mənada Yaratmağa bənzəyir, lakin fərq yolda .child (todo.key) əlavə edilməsidir.

_updateTodo (Todo todo) {// Tamamlanmış todo-ya keçid tamamlandı =! todo.tamamlandı; if (todo! = null) {_database.reference (). uşaq ("todo"). uşaq (todo.key) .set (todo.toJson ()); }}

Sil

Firebase-dən əşyaların silinməsi sadədir. Yeniləməyə bənzər şəkildə doğru todo.key-i əldə etməliyik, lakin .remove () metodundan istifadə edəcəyik.

Qeyd edək ki, əlavə edilmiş və ya dəyişdirilmiş əşyalar üçün dinləyicidən fərqli olaraq, elementləri silmək üçün dinləyici yoxdur. Beləliklə, bu 2 dinləyici metodunun atəş edə bilməsi və verilənlər bazasının son anını əldə edə biləcəyi bir yol yoxdur. Bu səbəbdən, elementi yalnız Firebase-dən silinməsi müvəffəq olduqda yerli _todoList dəyişkənliyimizdən əl ilə çıxarmalıyıq.
_deleteTodo (String todoId, int index) {_database.reference (). uşaq ("todo"). uşaq (todoId). sil (). sonra ((_) {print ("Uğurla $ todoId sil"); setState (() {_todoList.removeAt (index);});}); }

demo

Tətbiq belə görünür

Son tətbiqetmənin demosu

Github

Mənbə kodu mövcuddur:

https://github.com/tattwei46/flutter_login_demo

tanınma

Bu yazını oxumaq üçün vaxt ayırdığınız üçün təşəkkür edirik. Ümid edirəm Flutter ilə gözəl səyahətinizdə sizə kömək edəcəkdir. Faydalı olduğunu düşünürsənsə, xahiş edirəm bu kimi məqalələr yazmağa davam etməyimi məsləhət gör