iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Mobile Development

Flutter基礎入門系列 第 18

【Day 18】sqflite無法開啟電腦資料庫使用:用sqflite_ffi代替吧!

  • 分享至 

  • xImage
  •  

先來前提回顧一下:

在上一篇,筆者分享了如何解決Futurenon-Future這兩種不同類別物件的存取,在花了一點時間後,終於利用FutureBuilder解決了這個問題!本篇中將會先主要談論另一個問題(怎麼這麼多問題呀......),而想看關於FutureBuilder的讀者可以直接滑到下方的FutureBuilder該如何使用?


sqflite 無法開啟電腦中的資料庫

tldr
sqflite目前僅支援Android/iOS/MacOS的系統,sqflite_common_ffi增加Windows/Linux/> > DartVM/flutter的支援功能。

今日筆者在測試程式時,跳出了以下問題通知:

You must call `databaseFactory = databaseFactoryFfi;` before using global openDatabase API

所以,像所有遇到bug的人,理所當然的我就將這段文字複製後貼上Google做搜尋,而後便看到這個人給出的答案
https://ithelp.ithome.com.tw/upload/images/20241002/201694467wyX7HhmsN.png
不知看到這裡的讀者是否會與筆者產生相同的問題:「這個package是什麼?為何要用它?」

而後筆者在尋找sqflite_common_ffi說明時則看到了這篇官方文件:Using sqflite_ffi instead of sqflite

想做資料庫的基礎編輯與操作,需要使用到DatabaseFactory這一個類別,而sqflite理想中能夠直接提供一個該類別的物件databaseFactoryFFi,但目前這個package還沒有完全製作好,仍有一些不足的地方,因此要使用sqflite_common_ffi來輔助部份作業系統。

設定與使用

dependencies

// pubspec.yaml
dependencies:
  sqflite_common_ffi: [version]
  sqlite3_flutter_libs: [version] // for ios/android/macos

其中,sqflite已經包含在sqflite_common_ffi之中,因此可將其從dependencies中移除

初始化

import 'package:sqflite_common_ffi/sqflite_ffi.dart';

Future main() async {
  if (Platform.isWindows || Platform.isLinux) {
    // Initialize FFI
    sqfliteFfiInit();
  }
  // Change the default factory. On iOS/Android, if not using `sqlite_flutter_lib` you can forget
  // this step, it will use the sqlite version available on the system.
  databaseFactory = databaseFactoryFfi;
  runApp(MyApp());
}

注意事項

  1. sqfliteFfiInit()是用於方便開發而使用的函式,我們可以將此部份自行做更動以自訂設定內容(尋找與讀取sqlite的shared library)
  2. 開啟資料庫時常與openDatabase()一起使用的getDatabasesPath()目前與ffi一同使用時並不穩定,可能會出現bug,建議使用其他方式獲得資料庫路徑,如path_provider

FutureBuilder該如何使用?

以下為筆者目前於Todo頁面所編寫的內容:

import 'package:flutter/material.dart';
import 'package:schedrag/data/models/child_blocks.dart';

class TodoPage extends StatefulWidget {
  final TextStyle optionStyle;
  const TodoPage(this.optionStyle, {super.key});

  @override
  State<TodoPage> createState() => _TodoPageState();
}

class _TodoPageState extends State<TodoPage> {
  final TimeBlocksDb db = TimeBlocksDb();
  late Future<List<TimeBlock>?> dbList;
  int num = 0;

  @override
  void initState() {
    dbList = db.getAll();
    super.initState();
  }

  @override
  Widget build(context) {
    return Scaffold(
      body: FutureBuilder<List<TimeBlock>?>(
        builder: (con, snap) {
          if (snap.hasData) {
            return ListView.builder(
              itemCount: snap.data!.length,
              itemBuilder: (context, index) {
                return ListTile(
                    title: Text(snap.data![index].name.toString()),
                    onTap: () {});
              },
            );
          } else {
            return const Center(
                child: Text("There isn't any todo being created yet."));
          }
        },
        future: dbList,
      ),
      floatingActionButton: FloatingActionButton(
        // add new timeblock
        onPressed: () {
          db.insert(TimeBlock.name('name_$num'));
          print('name_$num\n');
          num++;
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}

可以看到該頁面主要是由FutureBuilder作為body的widget所組成,且FutureBuilder主要包含以下兩樣內容:futurebuilder

future:將要存取資料的變數

這一欄將會放一個物件類別為Future<[ObjectType]?>的變數,其中,中括號內的資料類別與上方的FutureBuilder<[ObjectType]>中相同。

late Future<List<TimeBlock>?> dbList;

...

    body: FutureBuilder<List<TimeBlock>?>(
      builder: ...
      future: dbList,
    ),

builder:欲建立的內容

https://ithelp.ithome.com.tw/upload/images/20241003/20169446afmCL9Wmci.png
上方圖片中有標記部份參數的資料型態。可以看出,builder一欄的物件為:Widget? function(BuildContext, AsyncSnapshot<[ObjectType]?>),一個回傳null或widget的函式,並能夠有一個snapshot的變數,作為之後存取future欄位資料的媒介。

關於AsyncSnapshot說明文件請點此
程式中利用該類別的properties: hasData來看是否有獲取資料、data來得到從future中最新獲得的資料。


謝謝讀到這裡的人,因為目前程式中仍有著bug,因此目前將不在此放上其他有做更動的部份的程式碼。至於nnyjan02426/Schedrag將會持續同步更新,有興趣的人可至那裡看到詳細內容。
如果有任何想說的內容,都可以留言或是email~
email: nnyjan02426@gmail.com
github: nnyjan02426


上一篇
【Day 17】嘗試解決問題:Future 與 non-Future類別間的存取
下一篇
【Day 19】利用path_provider開啟資料夾與檔案
系列文
Flutter基礎入門30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言