FlutterとDB(SQLite)の小話。

FlutterとDB

現在公開しておりますアプリを作る際に、最初に現れたある意味強敵です。

アプリの方は

GooglePlay「Nagare」

AppStore「Nagare」

からどうぞどうぞよろしくおねがいします。

さてなぜ強敵だったのか・・・
そして、SQLiteを使うとなにがよろしいのかというお話が主でございます。

SQLの利点。

一番の利点はやはり、データの永続化、そしてそのデータの永続化と
情報の「追加」「更新」「読み込み」に「SQL」がつかえることです。
SQLは、業務システムでもWebのシステムでもよく耳にすることもあろうかと思います。
「SELECT * FROM user WHERE user_id = 'test'」みたいなやつです。
これが使えるのがなにがよろしいか。
自前でファイル実装した際にさて、データの何行目のなんのデータがほしいとなると
結構な苦労がありそうな気配がしますが、SQLであればSELECT条件でスパッと抜けてきます。
これが最大便利なんではないかと考えております。
これをやはり使いたくなってしまうのが、業務系をしてしまっていた私の癖なのかもしれませんが
Androidには「SQLite」と言うファイルベースのSQLエンジンがあるではないですか!
使わない手はありません。

FlutterでSQLiteを使うには

FlutterでSQLiteを利用するには

sqflite

のパッケージを使うのがよろしいでしょう。
ありがたいことにたくさんの有志がたくさんのパッケージを作ってくれているのが
このFlutterの有り難さです。
人の優しさに全力で甘えましょう。自前で作ると地獄を見そうなので。

このパッケージを
Flutterプロジェクト内のファイル
「pubspec.yaml」の「dependencies」のところに追加しましょう。
適切にバージョンも指定しましょう。
2019年10月25日現在、この「sqflite」のバージョンは、「1.1.7+1」ですので指定方法は

sqflite: ^1.1.7+1

になります。
あとはVisualStudioCodeであれば勝手にファイルが落ちてくれるはずですが
様子がおかしい場合は

「flutter pub get 」のコマンドで自分で取得しましょう。

少しだけ覗く

Flutterがなんでマルチデバイス(Android、iOS」を一つのソースでできるのか・・・
その秘密の一端は皆様、有志の方が作ってくれているソースを見ると一端を知ることができます。

https://github.com/tekartik/sqflite

そこには「Android」と「iOS」のディレクトリが存在しています。
中身を見てみると・・・
JavaとObjective-Cのソースが・・・
有志の方々のおかげでFlutterで作る分にはこのソースを意識しないで済んでいます。ありがたいことです。

早速FlutterでSQLiteをしよう

早速実装しようとするとこれが言うことを聞いてくれません。
データベースのオブジェクトが生成される前に、SQL文を発行しようとしてコケるわけです。
なぜだ・・・
以下、公式のサンプルを抜粋してきました

class TodoProvider {
  Database db;
  Future open(String path) async {
    db = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute('''
create table $tableTodo ( 
  $columnId integer primary key autoincrement, 
  $columnTitle text not null,
  $columnDone integer not null)
''');
    });
  }
  Future insert(Todo todo) async {
    todo.id = await db.insert(tableTodo, todo.toMap());
    return todo;
  }
  Future getTodo(int id) async {
    List maps = await db.query(tableTodo,
        columns: [columnId, columnDone, columnTitle],
        where: '$columnId = ?',
        whereArgs: [id]);
    if (maps.length > 0) {
      return Todo.fromMap(maps.first);
    }
    return null;
  }
  Future delete(int id) async {
    return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]);
  }
  Future update(Todo todo) async {
    return await db.update(tableTodo, todo.toMap(),
        where: '$columnId = ?', whereArgs: [todo.id]);
  }
  Future close() async => db.close();
}

さて私も教科書どおりに進めましたが・・・なぜかうまくいきませんでしたここからは
試行錯誤とGoogle先生へのお尋ね(検索)をひたすら続け
Try&Errorです

で結果的にうまく言ったのは以下のようなパターンでした。

class TestProvider {
  TestProvider._();
  
  static final TestProvider db = TestProvider._();
  static Database _database;
  Future get database async {
    if (_database != null)
      return _database;
    _database = await initDB();
    return _database;
  }
  initDB() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "test.db");
    return await openDatabase(path, version: 1, onOpen: (db) {},
      onCreate: (Database db, int version) async {
        await db.execute("""
        CREATE TABLE test(
            id TEXT,
            comment TEXT
          )
        """);
    });
  }
  
  Future newDataInsert(Test t) async {
    final db = await database;
    var res = await db.rawQuery("select * from test where uid = ? ", [t.getId()]);
    var result;
    if (res.length == 0) {
      result = await db.rawInsert(
        "INSERT INTO test (id, comment) VALUES (?, ?)",
        [t.getId(), t.getComment()]
      );
    }
    
    return result;
  }
}

ある意味自分が忘れてしまわないようにするためのメモでございます・・・

利用する場合

Test t  = new Test();
var result = TestProvider .db.newDataInsert(t);
のようにします。
もちろん
Test t  = new Test();
TestProvider .db.newDataInsert(t).then((var result) {
//////
});

でもよろしいかと。

当初作り始めたとき・・・そこまで引っかかることもなく
なんとか作れていたFlutterでのアプリ開発の最初の難関でありました。

今思えば呼び出し方やらなんやらが問題でサンプルはちゃんと動くようにも思います・・・
まあ・・・それはそれと言うことでひとつ・・・

2019-10-25 08:51:53

Writer:ゆたさん@開発者。

HomePagehome Twitter Facebook
「FlutterとDB(SQLite)の小話。」をシェアしませんか?

最新ページ

  • またMVCを作り始めたお話し

    今回はプライベートではなくてオープンなリポジトリとしてGitHubでリポジトリ管理しています。OreOreMVCNagare(つまりここの)MVCの置き換えもし...
  • Steamのゲームでコントローラが効かなくなった時の対応

    環境M1 MacbookAirSteamPS5のコントローラをBluetoothで接続ゲームは、Vampire Survivorsです。現象Steamのコントロ...
  • 作る予定なもの各種。

    お世話になっております。お久しぶりです。Nagareについての記事でございます・・・Nagareのエンジニアのくせに全然、Nagareに関しまして最近発信してい...
  • メタメタメタメタメタバース

    最近やたらとメタバースメタバースと言う言葉が飛び交っております。やはりこのビッグウェーブには乗るしかないのでしょうか。問題はどう言う方法でこの「メタバース」の波...
  • 着手するまでが時間がかかると言うおはなし

    何かを始めようとするときに計画まではOKで実際に実行する時時間がかかりませんか?腰が重い・・・身体がダル重い感じが・・・こう・・・やる気がどこかに言ってしまって...