Flutter-데이터베이스 개념
Flutter는 데이터베이스 작업을위한 많은 고급 패키지를 제공합니다. 가장 중요한 패키지는 다음과 같습니다.
sqflite − SQLite 데이터베이스에 액세스하고 조작하는 데 사용됩니다.
firebase_database − Google의 클라우드 호스팅 NoSQL 데이터베이스에 액세스하고 조작하는 데 사용됩니다.
이 장에서는 각각에 대해 자세히 설명하겠습니다.
SQLite
SQLite 데이터베이스는 사실상 표준 SQL 기반 임베디드 데이터베이스 엔진입니다. 작고 오랜 시간 테스트를 거친 데이터베이스 엔진입니다. sqflite 패키지는 SQLite 데이터베이스에서 효율적으로 작업 할 수있는 많은 기능을 제공합니다. SQLite 데이터베이스 엔진을 조작하는 표준 방법을 제공합니다. sqflite 패키지가 제공하는 핵심 기능은 다음과 같습니다.
SQLite 데이터베이스를 생성 / 열기 (openDatabase 메서드)합니다.
SQLite 데이터베이스에 대해 SQL 문 (실행 메서드)을 실행합니다.
SQLite 데이터베이스에서 정보를 쿼리하고 가져 오는 데 필요한 코드로 줄이기위한 고급 쿼리 방법 (쿼리 방법).
sqflite 패키지를 사용하여 표준 SQLite 데이터베이스 엔진에서 제품 정보를 저장하고 가져 오는 제품 응용 프로그램을 만들고 SQLite 데이터베이스 및 sqflite 패키지의 개념을 이해하겠습니다.
Android 스튜디오 product_sqlite_app에서 새 Flutter 애플리케이션을 만듭니다.
기본 시작 코드 (main.dart)를 product_rest_app 코드로 바꿉니다 .
에서 폴더 자산을 복사 product_nav_app 에 product_rest_app 와 * 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
아래와 같이 pubspec.yaml 파일에서 sqflite 패키지를 구성하십시오.
dependencies: sqflite: any
최신 버전의 sqflite를 사용하십시오.
아래와 같이 pubspec.yaml 파일에서 path_provider 패키지를 구성하십시오.
dependencies: path_provider: any
여기서 path_provider 패키지는 시스템의 임시 폴더 경로와 응용 프로그램의 경로를 가져 오는 데 사용됩니다. 최신 버전 번호 사용 sqflite를 대신에 어느 .
Android 스튜디오는 pubspec.yaml이 업데이트되었음을 알립니다.
종속성 가져 오기 옵션을 클릭하십시오. Android 스튜디오는 인터넷에서 패키지를 가져와 애플리케이션에 맞게 적절하게 구성합니다.
데이터베이스에서는 이름, 가격 등과 같은 Product 속성과 함께 추가 필드로 기본 키, id가 필요하므로 Product 클래스에 id 속성을 추가합니다. 또한 새로운 메소드 인 toMap을 추가하여 제품 객체를 Map 객체로 변환합니다. fromMap 및 toMap은 Product 개체를 직렬화 및 직렬화 해제하는 데 사용되며 데이터베이스 조작 방법에 사용됩니다.
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
};
}
SQLite 관련 기능 을 작성하려면 lib 폴더에 새 파일 Database.dart를 만듭니다 .
Database.dart에서 필요한 import 문을 가져옵니다.
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';
여기에서 다음 사항에 유의하십시오.
async 비동기 메서드를 작성하는 데 사용됩니다.
io 파일 및 디렉토리에 액세스하는 데 사용됩니다.
path 파일 경로와 관련된 다트 핵심 유틸리티 기능에 액세스하는 데 사용됩니다.
path_provider 임시 및 응용 프로그램 경로를 가져 오는 데 사용됩니다.
sqflite SQLite 데이터베이스를 조작하는 데 사용됩니다.
새 수업 만들기 SQLiteDbProvider
아래에 지정된대로 싱글 톤 기반의 정적 SQLiteDbProvider 객체를 선언합니다.
class SQLiteDbProvider {
SQLiteDbProvider._();
static final SQLiteDbProvider db = SQLiteDbProvider._();
static Database _database;
}
SQLiteDBProvoider 개체 및 해당 메서드는 정적 db 변수를 통해 액세스 할 수 있습니다.
SQLiteDBProvoider.db.<emthod>
Future <Database> 유형의 데이터베이스 (Future 옵션)를 가져 오는 메서드를 만듭니다. 제품 테이블을 생성하고 데이터베이스 자체를 생성하는 동안 초기 데이터를로드합니다.
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"]
);
}
);
}
여기에서는 다음과 같은 방법을 사용했습니다.
getApplicationDocumentsDirectory − 응용 프로그램 디렉토리 경로를 반환합니다.
join− 시스템 특정 경로를 생성하는 데 사용됩니다. 데이터베이스 경로를 만드는 데 사용했습니다.
openDatabase − SQLite 데이터베이스를 여는 데 사용
onOpen − 데이터베이스를 여는 동안 코드 작성에 사용
onCreate − 데이터베이스를 처음 생성하는 동안 코드 작성에 사용
db.execute− SQL 쿼리를 실행하는 데 사용됩니다. 쿼리를받습니다. 쿼리에 자리 표시 자 (?)가있는 경우 두 번째 인수의 목록으로 값을 허용합니다.
데이터베이스의 모든 제품을 얻는 방법을 작성하십시오-
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;
}
여기서 우리는 다음을 수행했습니다.
모든 제품 정보를 가져 오는 쿼리 방법을 사용했습니다. 쿼리는 전체 쿼리를 작성하지 않고 테이블 정보를 쿼리하는 바로 가기를 제공합니다. query 메소드는 column, orderBy 등과 같은 입력을 사용하여 적절한 쿼리 자체를 생성합니다.
Product의 fromMap 메서드를 사용하여 테이블의 모든 행을 보유하는 결과 개체를 반복하여 제품 세부 정보를 가져 왔습니다.
특정 제품을 얻기위한 방법 작성 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;
}
여기에서는 where 및 whereArgs를 사용하여 필터를 적용했습니다.
데이터베이스에서 제품을 삽입, 업데이트 및 삭제하는 세 가지 방법-삽입, 업데이트 및 삭제 방법을 만듭니다.
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]);
}
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';
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]);
}
}
제품 정보를 얻기 위해 주요 방법을 변경하십시오.
void main() {
runApp(MyApp(products: SQLiteDbProvider.db.getAllProducts()));
}
여기서는 getAllProducts 메소드를 사용하여 데이터베이스에서 모든 제품을 가져 왔습니다.
응용 프로그램을 실행하고 결과를 확인합니다. 제품 정보가 로컬 SQLite 데이터베이스에서 저장되고 가져온다는 점을 제외하면 이전 예제 인 Accessing Product service API 와 유사 합니다.
Cloud Firestore
Firebase는 BaaS 앱 개발 플랫폼입니다. 인증 서비스, 클라우드 스토리지 등과 같은 모바일 애플리케이션 개발 속도를 높이기위한 많은 기능을 제공합니다. Firebase의 주요 기능 중 하나는 클라우드 기반 실시간 NoSQL 데이터베이스 인 Cloud Firestore입니다.
Flutter는 Cloud Firestore로 프로그래밍 할 수있는 특별한 패키지 인 cloud_firestore를 제공합니다. Cloud Firestore에 온라인 제품 스토어를 만들고 제품 스토어에 액세스 할 수있는 애플리케이션을 만들어 보겠습니다.
Android 스튜디오 product_firebase_app에서 새 Flutter 애플리케이션을 만듭니다.
기본 시작 코드 (main.dart)를 product_rest_app 코드로 바꿉니다 .
product_rest_app의 Product.dart 파일을 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'],
);
}
}
product_rest_app에서 product_firebase_app으로 애셋 폴더를 복사하고 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
아래와 같이 pubspec.yaml 파일에서 cloud_firestore 패키지를 구성합니다.
dependencies: cloud_firestore: ^0.9.13+1
여기에서 최신 버전의 cloud_firestore 패키지를 사용합니다.
Android 스튜디오는 pubspec.yaml이 여기에 표시된대로 업데이트되었음을 경고합니다.
종속성 가져 오기 옵션을 클릭하십시오. Android 스튜디오는 인터넷에서 패키지를 가져와 애플리케이션에 맞게 적절하게 구성합니다.
다음 단계를 사용하여 Firebase에서 프로젝트를 만듭니다.
무료 요금제를 선택하여 Firebase 계정을 만듭니다. https://firebase.google.com/pricing/.
Firebase 계정이 생성되면 프로젝트 개요 페이지로 리디렉션됩니다. 모든 Firebase 기반 프로젝트를 나열하고 새 프로젝트를 만드는 옵션을 제공합니다.
프로젝트 추가를 클릭하면 프로젝트 생성 페이지가 열립니다.
프로젝트 이름으로 제품 앱 db를 입력하고 프로젝트 생성 옵션을 클릭합니다.
* Firebase 콘솔로 이동합니다.
프로젝트 개요를 클릭합니다. 프로젝트 개요 페이지가 열립니다.
안드로이드 아이콘을 클릭하세요. Android 개발에 특정한 프로젝트 설정이 열립니다.
Android 패키지 이름 com.tutorialspoint.flutterapp.product_firebase_app을 입력합니다.
앱 등록을 클릭합니다. 프로젝트 구성 파일 google_service.json을 생성합니다.
google_service.json을 다운로드 한 다음 프로젝트의 android / app 디렉토리로 이동합니다. 이 파일은 애플리케이션과 Firebase 간의 연결입니다.
android / app / build.gradle을 열고 다음 코드를 포함합니다.
apply plugin: 'com.google.gms.google-services'
android / build.gradle을 열고 다음 구성을 포함합니다.
buildscript {
repositories {
// ...
}
dependencies {
// ...
classpath 'com.google.gms:google-services:3.2.1' // new
}
}
android / app / build.gradle을 열고 다음 코드도 포함합니다.
여기서 플러그인과 클래스 경로는 google_service.json 파일을 읽을 목적으로 사용됩니다.
android {
defaultConfig {
...
multiDexEnabled true
}
...
}
dependencies {
...
compile 'com.android.support: multidex:1.0.3'
}
Firebase 콘솔의 나머지 단계를 따르거나 건너 뛰세요.
다음 단계를 사용하여 새로 생성 된 프로젝트에 제품 스토어를 생성합니다.
Firebase 콘솔로 이동합니다.
새로 생성 된 프로젝트를 엽니 다.
왼쪽 메뉴에서 데이터베이스 옵션을 클릭합니다.
데이터베이스 만들기 옵션을 클릭합니다.
테스트 모드에서 시작을 클릭 한 다음 활성화를 클릭합니다.
컬렉션 추가를 클릭합니다. 컬렉션 이름으로 제품을 입력하고 다음을 클릭합니다.
여기에 이미지와 같이 샘플 제품 정보를 입력하십시오-
이 종속성을 통해 Android 애플리케이션은 여러 dex 기능을 사용할 수 있습니다.
문서 추가 옵션을 사용하여 제품 정보를 추가합니다 .
main.dart 파일을 열고 Cloud Firestore 플러그인 파일을 가져온 다음 http 패키지를 제거합니다.
import 'package:cloud_firestore/cloud_firestore.dart';
parseProducts를 제거하고 fetchProducts를 업데이트하여 제품 서비스 API 대신 Cloud Firestore에서 제품을 가져옵니다.
Stream<QuerySnapshot> fetchProducts() {
return Firestore.instance.collection('product').snapshots(); }
여기에서는 Firestore.instance.collection 메소드를 사용하여 클라우드 스토어에서 제공되는 제품 컬렉션에 액세스합니다. Firestore.instance.collection은 컬렉션을 필터링하여 필요한 문서를 가져 오는 다양한 옵션을 제공합니다. 그러나 모든 제품 정보를 얻기 위해 필터를 적용하지 않았습니다.
Cloud Firestore는 Dart Stream 개념을 통해 컬렉션을 제공하므로 MyApp 및 MyHomePage 위젯의 제품 유형을 Future <list <Product >>에서 Stream <QuerySnapshot>으로 수정합니다.
FutureBuilder 대신 StreamBuilder를 사용하도록 MyHomePage 위젯의 빌드 방법을 변경합니다.
@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());
}
},
),
)
);
}
여기서는 List <DocumentSnapshot> 유형으로 제품 정보를 가져 왔습니다. 위젯 인 ProductBoxList는 문서와 호환되지 않으므로 문서를 List <Product> 유형으로 변환하여 추가로 사용했습니다.
마지막으로 애플리케이션을 실행하고 결과를 확인합니다. SQLite 애플리케이션 과 동일한 제품 정보를 사용하고 저장 매체 만 변경 했기 때문에 결과 애플리케이션은 SQLite 애플리케이션 애플리케이션 과 동일하게 보입니다 .