Halo, Habr! Kami sajikan kepada Anda terjemahan artikel
“Menggunakan SQLite di Flutter” .

Menyimpan data sangat penting bagi pengguna, karena tidak praktis untuk memuat data yang sama dari jaringan. Akan lebih bijaksana untuk menyelamatkan mereka secara lokal.
Pada artikel ini, saya akan menunjukkan cara melakukan ini menggunakan SQLite di Flutter-e
Mengapa SQLite?
SQLite adalah cara paling populer untuk menyimpan data di perangkat seluler. Pada artikel ini, kita akan menggunakan paket sqflite untuk menggunakan SQLite. Sqflite adalah salah satu pustaka yang paling sering digunakan dan relevan untuk menghubungkan database SQLite ke Flutter.
1. Tambahkan dependensi
Dalam proyek kami, buka file
pubspec.yaml . Di bawah dependensi, tambahkan versi terbaru dari sqflite dan path_provider.
dependencies: flutter: sdk: flutter sqflite: any path_provider: any
2. Buat Klien DB
Sekarang buat file Database.dart baru. Di dalamnya, buat singleton.
Mengapa kami membutuhkan singleton: kami menggunakan pola ini untuk memastikan bahwa kami hanya memiliki satu entitas kelas dan untuk memberikan titik masuk global ke dalamnya.
1. Buat konstruktor pribadi yang hanya dapat digunakan di dalam kelas ini.
class DBProvider { DBProvider._(); static final DBProvider db = DBProvider._(); }
2. Atur database
Langkah selanjutnya adalah membuat objek database dan menyediakan pengambil di mana kita akan membuat objek database jika belum dibuat (inisialisasi malas)
static Database _database; Future<Database> get database async { if (_database != null) return _database; // if _database is null we instantiate it _database = await initDB(); return _database; }
Jika tidak ada objek yang ditugaskan ke database, maka kita akan memanggil fungsi initDB untuk membuat database. Dalam fungsi ini, kita mendapatkan jalur untuk menyimpan database dan membuat tabel yang diinginkan
initDB() async { Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(documentsDirectory.path, "TestDB.db"); return await openDatabase(path, version: 1, onOpen: (db) { }, onCreate: (Database db, int version) async { await db.execute("CREATE TABLE Client (" "id INTEGER PRIMARY KEY," "first_name TEXT," "last_name TEXT," "blocked BIT" ")"); }); }
3. Buat kelas model
Data di dalam basis data akan dikonversi ke Peta Dart. Kita perlu membuat kelas model dengan metode toMap dan fromMap.
Untuk membuat kelas model, saya akan menggunakan
situs ini
Model kami:
/// ClientModel.dart import 'dart:convert'; Client clientFromJson(String str) { final jsonData = json.decode(str); return Client.fromJson(jsonData); } String clientToJson(Client data) { final dyn = data.toJson(); return json.encode(dyn); } class Client { int id; String firstName; String lastName; bool blocked; Client({ this.id, this.firstName, this.lastName, this.blocked, }); factory Client.fromJson(Map<String, dynamic> json) => new Client( id: json["id"], firstName: json["first_name"], lastName: json["last_name"], blocked: json["blocked"], ); Map<String, dynamic> toJson() => { "id": id, "first_name": firstName, "last_name": lastName, "blocked": blocked, }; }
4. Operasi CRUD
BuatMenggunakan rawInsert:
newClient(Client newClient) async { final db = await database; var res = await db.rawInsert( "INSERT Into Client (id,first_name)" " VALUES (${newClient.id},${newClient.firstName})"); return res; }
Menggunakan insert:
newClient(Client newClient) async { final db = await database; var res = await db.insert("Client", newClient.toMap()); return res; }
Contoh lain menggunakan ID besar sebagai ID baru
newClient(Client newClient) async { final db = await database; //get the biggest id in the table var table = await db.rawQuery("SELECT MAX(id)+1 as id FROM Client"); int id = table.first["id"]; //insert to the table using the new id var raw = await db.rawInsert( "INSERT Into Client (id,first_name,last_name,blocked)" " VALUES (?,?,?,?)", [id, newClient.firstName, newClient.lastName, newClient.blocked]); return raw; }
BacaDapatkan Klien melalui id
getClient(int id) async { final db = await database; var res =await db.query("Client", where: "id = ?", whereArgs: [id]); return res.isNotEmpty ? Client.fromMap(res.first) : Null ; }
Dapatkan semua Klien dengan suatu syarat
getAllClients() async { final db = await database; var res = await db.query("Client"); List<Client> list = res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : []; return list; }
Dapatkan hanya pelanggan yang diblokir
getBlockedClients() async { final db = await database; var res = await db.rawQuery("SELECT * FROM Client WHERE blocked=1"); List<Client> list = res.isNotEmpty ? res.toList().map((c) => Client.fromMap(c)) : null; return list; }
PerbaruiPerbarui Klien yang ada
updateClient(Client newClient) async { final db = await database; var res = await db.update("Client", newClient.toMap(), where: "id = ?", whereArgs: [newClient.id]); return res; }
Client Lock / Unlock
blockOrUnblock(Client client) async { final db = await database; Client blocked = Client( id: client.id, firstName: client.firstName, lastName: client.lastName, blocked: !client.blocked); var res = await db.update("Client", blocked.toMap(), where: "id = ?", whereArgs: [client.id]); return res; }
HapusHapus satu Klien
deleteClient(int id) async { final db = await database; db.delete("Client", where: "id = ?", whereArgs: [id]); }
Hapus Semua Klien
deleteAll() async { final db = await database; db.rawDelete("Delete * from Client"); }
Demo
Untuk demo kami, kami akan membuat aplikasi sederhana yang menampilkan basis data kami.
Pertama-tama kita membuat layar
Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("Flutter SQLite")), body: FutureBuilder<List<Client>>( future: DBProvider.db.getAllClients(), builder: (BuildContext context, AsyncSnapshot<List<Client>> snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (BuildContext context, int index) { Client item = snapshot.data[index]; return ListTile( title: Text(item.lastName), leading: Text(item.id.toString()), trailing: Checkbox( onChanged: (bool value) { DBProvider.db.blockClient(item); setState(() {}); }, value: item.blocked, ), ); }, ); } else { return Center(child: CircularProgressIndicator()); } }, ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () async { Client rnd = testClients[math.Random().nextInt(testClients.length)]; await DBProvider.db.newClient(rnd); setState(() {}); }, ), ); }
Catatan:
1. FutureBuilder digunakan untuk mendapatkan data dari database
2. FAB untuk menginisialisasi klien uji
List<Client> testClients = [ Client(firstName: "Raouf", lastName: "Rahiche", blocked: false), Client(firstName: "Zaki", lastName: "oun", blocked: true), Client(firstName: "oussama", lastName: "ali", blocked: false), ];
3. CircularProgressIndicator ditampilkan ketika tidak ada data.
4. Ketika pengguna mengklik pada kotak centang, klien diblokir / tidak dikunci
Sekarang sangat mudah untuk menambahkan fitur-fitur baru, misalnya, jika kita ingin menghapus klien ketika digesek, cukup bungkus ListTile dalam widget Dismissible seperti ini:
return Dismissible( key: UniqueKey(), background: Container(color: Colors.red), onDismissed: (direction) { DBProvider.db.deleteClient(item.id); }, child: ListTile(...), );
Refactoring untuk menggunakan pola BLoC
Kami telah melakukan banyak hal dalam artikel ini, tetapi dalam aplikasi dunia nyata, menginisialisasi keadaan di lapisan UI bukanlah ide yang baik. Pisahkan logika dari UI.
Ada banyak pola dalam Flutter, tetapi kami akan menggunakan BLoC karena merupakan yang paling fleksibel untuk penyesuaian.
Buat BLoC class ClientsBloc { ClientsBloc() { getClients(); } final _clientController = StreamController<List<Client>>.broadcast(); get clients => _clientController.stream; dispose() { _clientController.close(); } getClients() async { _clientController.sink.add(await DBProvider.db.getAllClients()); } }
Catatan:
Catatan:
1. getClients menerima data dari basis data (tabel Klien) secara tidak sinkron. Kami akan menggunakan metode ini setiap kali kami perlu memperbarui tabel, oleh karena itu ada baiknya menempatkannya di tubuh konstruktor.
2. Kami membuat StreamController.broadcast untuk mendengarkan acara siaran lebih dari sekali. Dalam contoh kita, ini tidak terlalu penting, karena kita hanya mendengarkannya sekali saja, tetapi akan menyenangkan untuk mengimplementasikan ini untuk masa depan.
3. Jangan lupa untuk menutup utas. Dengan cara ini kita akan mencegah peringatan. Dalam contoh kami, kami menutupnya menggunakan metode buang di StatefulWidget
Sekarang lihat kodenya
blockUnblock(Client client) { DBProvider.db.blockOrUnblock(client); getClients(); } delete(int id) { DBProvider.db.deleteClient(id); getClients(); } add(Client client) { DBProvider.db.newClient(client); getClients(); }
Dan akhirnya hasil akhirnya
Sumber dapat ditemukan di sini -
Github