Table of contents
오늘한일
플러터 1/4/7/14 앱
db 적용
sqflite, jaguar_orm를 적용하려 했으나, 코드가 더 길어지는 것 같아서 그냥 sembast를 사용하기로 했다.
sembast는 key-value db이므로 데이터 대부분이 json이라면 document db인 objectdb를 사용하는 것을 추천한다.
dart의 in-momory는 대부분 비동기로 동작하는 듯 하다 (심지어 db connection 생성도 비동기다). 내가 선택한 sembast도 그렇다. 그런데, flutter widget의 build 메소드가 동기로 동작해서 reorder 기능을 구현하기가 힘들었다. 이번에도 구글링이 전부 해결해줬다.
class SubjectDatabase {
static final SubjectDatabase _instance = new SubjectDatabase.internal();
factory SubjectDatabase() => _instance;
static Database _db;
static StoreRef _store;
Future<SubjectDatabase> get() async {
if (_db != null) return _instance;
await initDb();
return _instance;
}
SubjectDatabase.internal();
initDb() async {
Directory appDocDirectory = await getApplicationDocumentsDirectory();
_db = await databaseFactoryIo
.openDatabase(join(appDocDirectory.path, '.dart_tool', 'sembast', 'example', 'record_demo.db'));
_store = intMapStoreFactory.store('my_store');
}
Future<List<Subject>> findAll() async {
var snapshots = await _store.find(_db, finder: Finder(
sortOrders: [SortOrder('pos')]
));
return snapshots.map((snapshot) {
return Subject.fromRecord(snapshot.key, snapshot.value);
}).toList();
}
updatePosition(int oldIndex, int newIndex) async {
List<Subject> subjects = await findAll();
Subject row = subjects.removeAt(oldIndex);
subjects.insert(newIndex, row);
for (var i = 0; i < subjects.length; i++) {
var record = _store.record(subjects[i].key);
await record.update(_db, {
'pos': i
});
}
}
}
// 비동기 widget builder
Future<List<Subject>> _subjectsFuture;
FutureBuilder(
future: _subjectsFuture,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else {
List<Subject> data = snapshot.data;
return ReorderableWrap(
children: data
.map((subject) => SubjectSizedCard(subject))
.toList(),
onReorder: updateAndRefresh,
maxMainAxisCount: 2,
);
}
}
}
void updateAndRefresh(int oldIndex, int newIndex) async {
await updatePosition(oldIndex, newIndex);
// reload
setState(() {
_subjectsFuture = findAll();
});
}
Future<List<Subject>> findAll() async {
var db = await SubjectDatabase().get();
return db.findAll();
}
updatePosition(int oldIndex, int newIndex) async {
var db = await SubjectDatabase().get();
await db.updatePosition(oldIndex, newIndex);
}
db 커넥션 생성비용 때문에 싱글턴을 적용했다. 아직은 updatePosition이 과목 전체를 업데이트하므로 효율이 떨어진다. 나중에 개선할 수 있으므로 우선은 여기까지...
오늘 느낀점
플러터가 좋기는 좋은데, 실용적인 예제가 별로 없는 것 같다. 예를 들어 비동기로 동작하는 데이터베이스와 CRUD 동작을 하는 StatefulWidget을 같이 사용하는 예제를 찾고 싶은데, 검색결과는 대부분 FutureBuilder와 Future<List>에 대한 내용이다. 결국 원하는 기능을 구현하기 위해서는 'async database example in flutter', 'FutureBuilder with StatefulWidget example' 를 각각 검색해야 한다.
제일 짜증나는 부분은 위젯 사이즈 조절하는데 자꾸 다른 위젯으로 감싸야 하는 부분이다. 자꾸 똑같은 내용을 검색하게되더라...
내일 할일
- 플러터 1/4/7/14 앱
- 과목 생성 기능 추가
- 배경색 선택 가능
- 과목 목록 표시
- 배경색의 밝기에 따라 글자색 white or black 표시
- 과목 생성 기능 추가