今日筆者將繼續在時刻表上做功能的設定,並且修改與優化過去的相關程式碼。下列為前幾篇與時刻表相關的文章:
【Day 26】建立客製化的時刻表吧!
【Day 27】儲存時刻表的新資料
到了鐵人賽末期就開始有點怠惰,懶的再回去修改之前的內容了_(¦3」∠)_
await open()
本次受到更動的檔案主要為data/models/blocks.dart
中的BlocksDb
,修改內容簡單來說,就是在各個函式中呼叫open()
時,先等待它跑完,再繼續執行下面的程式(就是加個await
keyword而已),避免資料庫未開啟就對資料庫做讀寫。
老實說,我是因為少了await而遇到了程式的bug,在那邊debug了半天,終於找到問題的關鍵 。゚(゚´ω`゚)゚。
詳細程式碼如下:blocks.dart
abstract class BlocksDb extends ChangeNotifier {
String dbFilename, tableName, executeSQL;
bool dbIsOpen;
Database? db;
BlocksDb(
{required this.dbFilename,
required this.tableName,
required this.executeSQL})
: dbIsOpen = false;
DateTime setTime(
{int month = 0, int day = 0, int hour = 0, int minute = 0}) =>
DateTime(2000, month, day, hour, minute);
Future<String> get _localPath async {...}
Future open() async {...}
Future<Block> insert(Block block) async {
if (!dbIsOpen) await open();
block.id = await db?.insert(tableName, block.toMap());
if (kDebugMode) {
print('$tableName: ${block.name} inserted');
}
notifyListeners();
return block;
}
Future<void> delete(int id) async {
if (!dbIsOpen) await open();
await db?.delete(tableName, where: 'id = ?', whereArgs: [id]);
notifyListeners();
}
Future<void> update(Block block) async {
if (!dbIsOpen) await open();
await db?.update(tableName, block.toMap(),
where: 'id = ?', whereArgs: [block.id]);
notifyListeners();
}
Future close() async {
dbIsOpen = false;
return await db?.close();
}
Future getCount() async =>
await db?.execute('SELECT COUNT(*) from $tableName');
}
time_blocks.dart
class TimeBlocksDb extends BlocksDb {
...
Future<List<TimeBlock>?> getAll() async {
if (!dbIsOpen) await open();
List<Map<String, Object?>>? table =
await db?.rawQuery('SELECT * FROM $tableName');
notifyListeners();
return table?.map((data) => TimeBlock().toBlock(data)).toList();
}
todo_blocks.dart
class TodoBlocksDb extends BlocksDb {
...
Future<List<TodoBlock>?> getAll() async {
if (!dbIsOpen) await open();
List<Map<String, Object?>>? table =
await db?.rawQuery('SELECT * FROM $tableName');
notifyListeners();
return table?.map((data) => TodoBlock().toBlock(data)).toList();
}
}
之前的程式中,將資料存於資料庫的動作是在_onCreateEvent
中執行,而筆者發現這會使得建立物件的結束時間永遠都在開始時間的15分鐘後,很明顯,這其中有個bug。後續發現儲存應該要改放在_onEventCreated
,也就是事件已經建立好了之後,再去執行。
應該也會有人跟筆者有相同的疑惑,這兩者間有什麼差別?在kalender的說明文件中是如此寫到:
我們可以將他們理解為:
那麼問題原因就很清楚啦!現在只要把insert()移到後者,問題就解決了!修改後的程式碼如下:
CalendarEvent<TimeBlock> _onCreateEvent(DateTimeRange dateTimeRange) {
return CalendarEvent(
dateTimeRange: dateTimeRange,
eventData: TimeBlock.name('new event'),
);
}
Future<void> _onEventCreated(CalendarEvent<TimeBlock> event) async {
// Add the event to the events controller.
eventController.addEvent(event);
// Deselect the event.
eventController.deselectEvent();
event.eventData!.setTimes(event.start, event.end);
db?.insert(event.eventData!);
}
此部份為用於讀取過去使用者在Timetable頁面建立並存在資料庫中的資料,並將他們加回到Timetable頁面中。在此使用了then()
來等待資料庫開啟並對其中的資料做讀取。
class _TimetablePageState extends State<TimetablePage> {
...
TimeBlocks? db;
@override
void initState() {
super.initState();
// load events from database
db = TimeBlocksDb();
db?.getAll().then((List<TimeBlock>? timeblocksdb) {
if (timeblocksdb != null) {
for (TimeBlock block in timeblocksdb) {
eventController.addEvent(CalendarEvent(
dateTimeRange:
DateTimeRange(start: block.startTime, end: block.endTime),
eventData: block,
));
}
if (kDebugMode) {
print('Fetched ${timeblocksdb.length} events from the database');
}
} else if (kDebugMode) {
print('No events found in database');
}
});
}
...
}
謝謝閱讀到這裡的讀者,有任何想說的都歡迎留言與email,明天會繼續努力的!
- email: nnyjan02426@gmail.com
- github
- Schedrag
最後是筆者的一點小小內心戲**——**
今天debug花的時間比預計的還要多,因此沒辦法達成昨日預期的進度 (☍﹏⁰。),明天在世試看將它補上吧。