Flutter - Concetti di database
Flutter fornisce molti pacchetti avanzati per lavorare con i database. I pacchetti più importanti sono:
sqflite - Utilizzato per accedere e manipolare il database SQLite e
firebase_database - Utilizzato per accedere e manipolare il database NoSQL ospitato nel cloud di Google.
In questo capitolo, esaminiamo ciascuno di essi in dettaglio.
SQLite
Il database SQLite è il motore di database incorporato basato su SQL standard e di fatto. È un motore di database piccolo e collaudato nel tempo. Il pacchetto sqflite fornisce molte funzionalità per lavorare in modo efficiente con il database SQLite. Fornisce metodi standard per manipolare il motore di database SQLite. La funzionalità principale fornita dal pacchetto sqflite è la seguente:
Crea / Apri (metodo openDatabase) un database SQLite.
Eseguire l'istruzione SQL (metodo di esecuzione) sul database SQLite.
Metodi di query avanzati (metodo di query) per ridurre al codice richiesto per eseguire query e ottenere informazioni dal database SQLite.
Creiamo un'applicazione del prodotto per archiviare e recuperare le informazioni sul prodotto da un motore di database SQLite standard utilizzando il pacchetto sqflite e comprendere il concetto alla base del database SQLite e del pacchetto sqflite.
Crea una nuova applicazione Flutter in Android Studio, product_sqlite_app.
Sostituisci il codice di avvio predefinito (main.dart) con il nostro codice product_rest_app .
Copia la cartella degli asset da product_nav_app a product_rest_app e aggiungi gli asset all'interno del file * pubspec.yaml`.
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
Configura il pacchetto sqflite nel file pubspec.yaml come mostrato di seguito -
dependencies: sqflite: any
Usa il numero di versione più recente di sqflite al posto di qualsiasi
Configura il pacchetto path_provider nel file pubspec.yaml come mostrato di seguito -
dependencies: path_provider: any
Qui, il pacchetto path_provider viene utilizzato per ottenere il percorso della cartella temporanea del sistema e il percorso dell'applicazione. Usa il numero di versione più recente di sqflite al posto di qualsiasi .
Android Studio avviserà che pubspec.yaml è aggiornato.
Fare clic sull'opzione Ottieni dipendenze. Android Studio otterrà il pacchetto da Internet e lo configurerà correttamente per l'applicazione.
Nel database, abbiamo bisogno della chiave primaria, id come campo aggiuntivo insieme alle proprietà del prodotto come nome, prezzo, ecc., Quindi, aggiungi la proprietà id nella classe Product. Inoltre, aggiungi un nuovo metodo, toMap per convertire l'oggetto del prodotto in un oggetto Map. fromMap e toMap sono usati per serializzare e deserializzare l'oggetto Product e sono usati nei metodi di manipolazione del database.
class Product {
final int id;
final String name;
final String description;
final int price;
final String image;
static final columns = ["id", "name", "description", "price", "image"];
Product(this.id, this.name, this.description, this.price, this.image);
factory Product.fromMap(Map<String, dynamic> data) {
return Product(
data['id'],
data['name'],
data['description'],
data['price'],
data['image'],
);
}
Map<String, dynamic> toMap() => {
"id": id,
"name": name,
"description": description,
"price": price,
"image": image
};
}
Crea un nuovo file, Database.dart nella cartella lib per scrivere le funzionalità relative a SQLite .
Importa l'istruzione di importazione necessaria in Database.dart.
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'Product.dart';
Nota i seguenti punti qui:
async viene utilizzato per scrivere metodi asincroni.
io viene utilizzato per accedere a file e directory.
path viene utilizzato per accedere alla funzione di utilità principale di dart relativa ai percorsi dei file.
path_provider viene utilizzato per ottenere il percorso temporaneo e dell'applicazione.
sqflite viene utilizzato per manipolare il database SQLite.
Crea una nuova classe SQLiteDbProvider
Dichiarare un oggetto SQLiteDbProvider statico basato su singleton come specificato di seguito -
class SQLiteDbProvider {
SQLiteDbProvider._();
static final SQLiteDbProvider db = SQLiteDbProvider._();
static Database _database;
}
È possibile accedere all'oggetto SQLiteDBProvoider e al relativo metodo tramite la variabile db statica.
SQLiteDBProvoider.db.<emthod>
Creare un metodo per ottenere il database (opzione Future) di tipo Future <Database>. Crea tabella prodotti e carica i dati iniziali durante la creazione del database stesso.
Future<Database> get database async {
if (_database != null)
return _database;
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "ProductDB.db");
return await openDatabase(
path,
version: 1,
onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE Product ("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
"description TEXT,"
"price INTEGER,"
"image TEXT" ")"
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone is the stylist phone ever", 1000, "iphone.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel is the most feature phone ever", 800, "pixel.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop is most productive development tool", 2000, "laptop.png"]\
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop is most productive development tool", 1500, "tablet.png"]
);
await db.execute(
"INSERT INTO Product
('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive is useful storage medium", 100, "pendrive.png"]
);
await db.execute(
"INSERT INTO Product
('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[6, "Floppy Drive", "Floppy drive is useful rescue storage medium", 20, "floppy.png"]
);
}
);
}
Qui abbiamo utilizzato i seguenti metodi:
getApplicationDocumentsDirectory - Restituisce il percorso della directory dell'applicazione
join- Utilizzato per creare un percorso specifico del sistema. Lo abbiamo usato per creare il percorso del database.
openDatabase - Usato per aprire un database SQLite
onOpen - Utilizzato per scrivere codice durante l'apertura di un database
onCreate - Utilizzato per scrivere codice durante la creazione di un database per la prima volta
db.execute- Utilizzato per eseguire query SQL. Accetta una query. Se la query ha un segnaposto (?), Accetta i valori come elenco nel secondo argomento.
Scrivi un metodo per ottenere tutti i prodotti nel database -
Future<List<Product>> getAllProducts() async {
final db = await database;
List<Map>
results = await db.query("Product", columns: Product.columns, orderBy: "id ASC");
List<Product> products = new List();
results.forEach((result) {
Product product = Product.fromMap(result);
products.add(product);
});
return products;
}
Qui, abbiamo fatto quanto segue:
Metodo di query utilizzato per recuperare tutte le informazioni sul prodotto. query fornisce un collegamento per interrogare le informazioni di una tabella senza scrivere l'intera query. il metodo query genererà la query corretta utilizzando il nostro input come colonne, orderBy, ecc.,
È stato utilizzato il metodo fromMap del prodotto per ottenere i dettagli del prodotto eseguendo il ciclo dell'oggetto risultati, che contiene tutte le righe della tabella.
Scrivi un metodo per ottenere un prodotto specifico id
Future<Product> getProductById(int id) async {
final db = await database;
var result = await db.query("Product", where: "id = ", whereArgs: [id]);
return result.isNotEmpty ? Product.fromMap(result.first) : Null;
}
Qui abbiamo usato where e whereArgs per applicare i filtri.
Crea tre metodi: inserisci, aggiorna ed elimina il metodo per inserire, aggiornare ed eliminare il prodotto dal database.
insert(Product product) async {
final db = await database;
var maxIdResult = await db.rawQuery(
"SELECT MAX(id)+1 as last_inserted_id FROM Product");
var id = maxIdResult.first["last_inserted_id"];
var result = await db.rawInsert(
"INSERT Into Product (id, name, description, price, image)"
" VALUES (?, ?, ?, ?, ?)",
[id, product.name, product.description, product.price, product.image]
);
return result;
}
update(Product product) async {
final db = await database;
var result = await db.update("Product", product.toMap(),
where: "id = ?", whereArgs: [product.id]); return result;
}
delete(int id) async {
final db = await database;
db.delete("Product", where: "id = ?", whereArgs: [id]);
}
Il codice finale di Database.dart è il seguente:
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'Product.dart';
class SQLiteDbProvider {
SQLiteDbProvider._();
static final SQLiteDbProvider db = SQLiteDbProvider._();
static Database _database;
Future<Database> get database async {
if (_database != null)
return _database;
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await
getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "ProductDB.db");
return await openDatabase(
path, version: 1,
onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE Product ("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
"description TEXT,"
"price INTEGER,"
"image TEXT"")"
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone is the stylist phone ever", 1000, "iphone.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel is the most feature phone ever", 800, "pixel.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop is most productive development tool", 2000, "laptop.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop is most productive development tool", 1500, "tablet.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive is useful storage medium", 100, "pendrive.png"]
);
await db.execute(
"INSERT INTO Product ('id', 'name', 'description', 'price', 'image')
values (?, ?, ?, ?, ?)",
[6, "Floppy Drive", "Floppy drive is useful rescue storage medium", 20, "floppy.png"]
);
}
);
}
Future<List<Product>> getAllProducts() async {
final db = await database;
List<Map> results = await db.query(
"Product", columns: Product.columns, orderBy: "id ASC"
);
List<Product> products = new List();
results.forEach((result) {
Product product = Product.fromMap(result);
products.add(product);
});
return products;
}
Future<Product> getProductById(int id) async {
final db = await database;
var result = await db.query("Product", where: "id = ", whereArgs: [id]);
return result.isNotEmpty ? Product.fromMap(result.first) : Null;
}
insert(Product product) async {
final db = await database;
var maxIdResult = await db.rawQuery("SELECT MAX(id)+1 as last_inserted_id FROM Product");
var id = maxIdResult.first["last_inserted_id"];
var result = await db.rawInsert(
"INSERT Into Product (id, name, description, price, image)"
" VALUES (?, ?, ?, ?, ?)",
[id, product.name, product.description, product.price, product.image]
);
return result;
}
update(Product product) async {
final db = await database;
var result = await db.update(
"Product", product.toMap(), where: "id = ?", whereArgs: [product.id]
);
return result;
}
delete(int id) async {
final db = await database;
db.delete("Product", where: "id = ?", whereArgs: [id]);
}
}
Modificare il metodo principale per ottenere le informazioni sul prodotto.
void main() {
runApp(MyApp(products: SQLiteDbProvider.db.getAllProducts()));
}
Qui abbiamo utilizzato il metodo getAllProducts per recuperare tutti i prodotti dal database.
Esegui l'applicazione e guarda i risultati. Sarà simile all'esempio precedente, Accesso all'API del servizio prodotto , tranne per il fatto che le informazioni sul prodotto vengono archiviate e recuperate dal database SQLite locale.
Cloud Firestore
Firebase è una piattaforma di sviluppo di app BaaS. Fornisce molte funzionalità per accelerare lo sviluppo di applicazioni mobili come il servizio di autenticazione, l'archiviazione su cloud, ecc. Una delle caratteristiche principali di Firebase è Cloud Firestore, un database NoSQL in tempo reale basato su cloud.
Flutter fornisce un pacchetto speciale, cloud_firestore da programmare con Cloud Firestore. Creiamo un negozio di prodotti online in Cloud Firestore e creiamo un'applicazione per accedere al negozio di prodotti.
Crea una nuova applicazione Flutter in Android Studio, product_firebase_app.
Sostituisci il codice di avvio predefinito (main.dart) con il nostro codice product_rest_app .
Copia il file Product.dart da product_rest_app nella cartella lib.
class Product {
final String name;
final String description;
final int price;
final String image;
Product(this.name, this.description, this.price, this.image);
factory Product.fromMap(Map<String, dynamic> json) {
return Product(
json['name'],
json['description'],
json['price'],
json['image'],
);
}
}
Copia la cartella degli asset da product_rest_app a product_firebase_app e aggiungi gli asset all'interno del file pubspec.yaml.
flutter:
assets:
- assets/appimages/floppy.png
- assets/appimages/iphone.png
- assets/appimages/laptop.png
- assets/appimages/pendrive.png
- assets/appimages/pixel.png
- assets/appimages/tablet.png
Configura il pacchetto cloud_firestore nel file pubspec.yaml come mostrato di seguito -
dependencies: cloud_firestore: ^0.9.13+1
Qui, usa l'ultima versione del pacchetto cloud_firestore.
Android Studio avviserà che pubspec.yaml è aggiornato come mostrato qui -
Fare clic sull'opzione Ottieni dipendenze. Android Studio otterrà il pacchetto da Internet e lo configurerà correttamente per l'applicazione.
Crea un progetto in Firebase utilizzando i seguenti passaggi:
Crea un account Firebase selezionando Piano gratuito su https://firebase.google.com/pricing/.
Una volta creato l'account Firebase, verrà reindirizzato alla pagina della panoramica del progetto. Elenca tutti i progetti basati su Firebase e fornisce un'opzione per creare un nuovo progetto.
Fare clic su Aggiungi progetto e si aprirà una pagina di creazione del progetto.
Immettere il db dell'app dei prodotti come nome del progetto e fare clic sull'opzione Crea progetto.
Vai a * Firebase console.
Fare clic su Panoramica del progetto. Apre la pagina di panoramica del progetto.
Fare clic sull'icona Android. Si aprirà l'impostazione del progetto specifica per lo sviluppo Android.
Inserisci il nome del pacchetto Android, com.tutorialspoint.flutterapp.product_firebase_app.
Fare clic su Registra app. Genera un file di configurazione del progetto, google_service.json.
Scarica google_service.json e spostalo nella directory android / app del progetto. Questo file è la connessione tra la nostra applicazione e Firebase.
Apri android / app / build.gradle e includi il seguente codice:
apply plugin: 'com.google.gms.google-services'
Apri android / build.gradle e includi la seguente configurazione:
buildscript {
repositories {
// ...
}
dependencies {
// ...
classpath 'com.google.gms:google-services:3.2.1' // new
}
}
Apri android / app / build.gradle e includi anche il seguente codice.
Qui, il plug-in e il percorso di classe vengono utilizzati allo scopo di leggere il file google_service.json.
android {
defaultConfig {
...
multiDexEnabled true
}
...
}
dependencies {
...
compile 'com.android.support: multidex:1.0.3'
}
Segui i passaggi rimanenti nella console Firebase o semplicemente saltali.
Creare un negozio di prodotti nel progetto appena creato utilizzando i seguenti passaggi:
Vai alla console Firebase.
Apri il progetto appena creato.
Fare clic sull'opzione Database nel menu a sinistra.
Fare clic sull'opzione Crea database.
Fare clic su Avvia in modalità test, quindi su Abilita.
Fai clic su Aggiungi raccolta. Immettere il prodotto come nome della raccolta e quindi fare clic su Avanti.
Immettere le informazioni sul prodotto di esempio come mostrato nell'immagine qui -
Questa dipendenza consente all'applicazione Android di utilizzare più funzionalità dex.
Aggiungere ulteriori informazioni sul prodotto utilizzando le opzioni Aggiungi documento .
Apri il file main.dart e importa il file del plug-in Cloud Firestore e rimuovi il pacchetto http.
import 'package:cloud_firestore/cloud_firestore.dart';
Rimuovi parseProducts e aggiorna fetchProducts per recuperare i prodotti da Cloud Firestore anziché dall'API del servizio prodotti.
Stream<QuerySnapshot> fetchProducts() {
return Firestore.instance.collection('product').snapshots(); }
Qui, il metodo Firestore.instance.collection viene utilizzato per accedere alla raccolta di prodotti disponibile nel cloud store. Firestore.instance.collection fornisce molte opzioni per filtrare la raccolta per ottenere i documenti necessari. Tuttavia, non abbiamo applicato alcun filtro per ottenere tutte le informazioni sul prodotto.
Cloud Firestore fornisce la raccolta tramite il concetto di Dart Stream e quindi modifica il tipo di prodotti nel widget MyApp e MyHomePage da Future <list <Product>> a Stream <QuerySnapshot>.
Modificare il metodo di creazione del widget MyHomePage per utilizzare StreamBuilder invece di FutureBuilder.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Product Navigation")),
body: Center(
child: StreamBuilder<QuerySnapshot>(
stream: products, builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
if(snapshot.hasData) {
List<DocumentSnapshot>
documents = snapshot.data.documents;
List<Product>
items = List<Product>();
for(var i = 0; i < documents.length; i++) {
DocumentSnapshot document = documents[i];
items.add(Product.fromMap(document.data));
}
return ProductBoxList(items: items);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
)
);
}
Qui, abbiamo recuperato le informazioni sul prodotto come tipo List <DocumentSnapshot>. Poiché il nostro widget ProductBoxList non è compatibile con i documenti, abbiamo convertito i documenti nel tipo List <Product> e li abbiamo ulteriormente utilizzati.
Infine, esegui l'applicazione e guarda il risultato. Poiché abbiamo utilizzato le stesse informazioni sul prodotto dell'applicazione SQLite e modificato solo il supporto di memorizzazione, l'applicazione risultante sembra identica all'applicazione dell'applicazione SQLite .