Flutter - 로컬 데이터베이스 ④: 이미지 파일을 데이터베이스에 저장하고 읽기
목차
1: Flutter - 로컬 데이터베이스 ①: sqflite(생성, 삽입, 업데이트, 삭제, 쿼리)
sqflite
를 사용하여Specs(id, type, category, method, contents, money, dateTime)
라는 로컬 데이터베이스를 생성- 로컬 데이터베이스에 접근하는
SpecProvider
클래스를 생성하고, DB에 읽고 쓰는 함수들을 정의
2: Flutter - 로컬 데이터베이스 ②: Future(데이터베이스 화면에 띄우기, FutureBuilder)
- DB에 접근하는 것은
async
한 작업 - 이를
Future
키워드를 사용해 다루고,FutureBuilder
로 화면에 값을 보여줌
3: Flutter - 로컬 데이터베이스 ③: Singleton, factory
- DB 인스턴스를 Singleton으로 생성
4: Flutter - 로컬 데이터베이스 ④: 이미지 파일을 데이터베이스에 저장하고 읽기 <현재>현재>
- 이미지 파일을 데이터베이스에 저장하고 읽기
이미지를 데이터베이스에 저장하자
이미지 데이터베이스에 저장하기
클래스 생성
일단 이미지 클래스를 만들자
현재 만들고 있는 앱은 각 spec 마다 이미지가 여러 장 추가될 수 있다. 따라서 Picture(id, specID, picture)
로 생성하기로 한다. id
는 이미지의 id로, 삭제할 때 접근하는 Primary Key다. specID
는 각 spec들이 가진 고유한 id로, spec에 포함된 이미지들을 찾을 때 접근한다. picture
는 저장될 실제 데이터다.
class Picture {
int? id;
int specID;
Uint8List picture;
Picture({this.id, required this.specID, required this.picture});
Map<String, dynamic> toMap(){
return {
"id": id,
"specID": specID,
"picture" : picture,
};
}
}
생성자와 데이터베이스에 저장해주기 위해 Map으로 변환해주는 함수를 정의한다.
PicProvider 클래스, db 테이블 생성
class PicProvider {
static final PicProvider _picProvider = PicProvider._internal();
PicProvider._internal(){
// init values...
/*
async cannot be used in constructor
*/
}
factory PicProvider() {
return _picProvider;
}
static Database? _database;
Future<Database> get database async => _database ??= await initDB();
initDB() async {
String path = join(await getDatabasesPath(), 'Pics.db');
return await openDatabase(
path,
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE Pics(
id INTEGER PRIMARY KEY AUTOINCREMENT,
specID INTEGER NOT NULL,
picture BLOB NOT NULL
)
''');
},
onUpgrade: (db, oldVersion, newVersion){}
);
}
Future<void> insert(Picture pic) async {
final db = await database;
print("Pics insert ${pic.specID}");
pic.id = await db?.insert(picTableName, pic.toMap());
}
Future<void> delete(Picture pic) async {
final db = await database;
print("Pics delete ${pic.specID}");
await db?.delete(
picTableName,
where: "id = ?",
whereArgs: [pic.id],
);
}
Future<void> deleteSpec(int specID) async {
final db = await database;
print("Pics delete all ${specID}");
await db?.delete(
picTableName,
where: "specID = ?",
whereArgs: [specID],
);
}
Future<List<Picture>> getDB() async {
final db = await database;
final List<Map<String, dynamic>> maps = await db!.query(picTableName);
if( maps.isEmpty ) return [];
List<Picture> list = List.generate(maps.length, (index) {
return Picture(
id: maps[index]["id"],
specID: maps[index]["specID"],
picture: maps[index]["picture"],
);
});
return list;
}
Future<List<Picture>> getQuery(String query) async {
final db = await database;
final List<Map<String, dynamic>> maps = await db!.rawQuery(query);
if( maps.isEmpty ) return [];
List<Picture> list = List.generate(maps.length, (index) {
return Picture(
id: maps[index]["id"],
specID: maps[index]["specID"],
picture: maps[index]["picture"],
);
});
return list;
}
}
생성과 insert, delete 등의 함수들은 이전 포스트와 비슷하다.
이미지 Uint8List로 변환하기
XFile? image = await picker.pickImage();
picProvider.insert(Picture(specID: spec.id!, picture: await image.readAsBytes()));
image picker로 받아온 이미지들은 XFile
타입이다. 이것을 readAsBytes()
로 읽어 Uint8List로 변환할 수 있다.
단, readAsBytes()
의 반환 타입은 Future<Uint8List>
이므로 await
해서 기다려 줘야 한다.
Uint8List로 이미지 만들기
Image.memory(Uint8List bytes);
// in this database
Picture pic;
Image.memory(pic.picture)
XFile로 이미지 만들기
Image.file(File(image.path))
굿
댓글남기기