Flutter SQFliteチュートリアルと例題

flutterでSQLite datbaseを扱う方法。

Flutterとは?

*Flutterは、iOSやAndroidの高品質なネイティブインターフェースを記録的な速さで作成するためのGoogleのモバイルアプリSDKです。

Flutterは、既存のコードで動作し、世界中の開発者や組織で使用されており、無料でオープンソースです。

Flutterの主な特徴は以下の3つです。

**1. 迅速な開発***。

Flutterは、ホットリロードにより、数ミリ秒でアプリに命を吹き込むことができます。

また、完全にカスタマイズ可能なウィジェットの豊富なセットを使用して、数分でネイティブなインターフェースを構築することができます。

2. 表現力豊かで柔軟なUI 2.

Flutterは、ネイティブなエンドユーザー体験を重視した機能を素早く提供することができます。

レイヤードアーキテクチャにより、完全なカスタマイズが可能なため、驚くほど高速なレンダリングと、表現力豊かで柔軟なデザインを実現します。

3. ネイティブなパフォーマンス

Flutterのウィジェットは、スクロール、ナビゲーション、アイコン、フォントなどの重要なプラットフォームの違いをすべて取り入れ、iOSとAndroidの両方で完全なネイティブパフォーマンスを提供します。

SQFliteとは?

SQfliteは、flutterのプラグインです。SQfliteはflutterのプラグインで、flutterのコードを使ってSQLiteデータベースを保存、取得、操作することができます。SQfliteは、AndroidとiOSの両方のプラットフォームに対応しています。

SQfliteの特徴は以下の通りです。

  1. SQFliteは、データベースのトランザクションとバッチの両方を提供します。
  2. SQliteは、自動バージョン管理を内蔵しています。
  3. SQFliteは、データベースへのデータの挿入、照会、更新、削除を簡単に行うことができます。
    1. これらのCRUD操作は、iOSとAndroidの両方で、バックグラウンドスレッドで実行されます。これにより、UI の応答性を維持することができます。

SQFliteのインストール方法

SQFliteのインストールは、他のflutterパッケージと同様に簡単です。SQFliteはDart Package Repositoryでホストされており、依存関係にあるパッケージとして追加することができます。

インストール方法は以下の通りです。

**1. あなたのpubspec.yamlファイルに移動します。

そして、それを依存関係として追加します。

dependencies:
  sqflite: ^0.12.1

最新のバージョンはこちらで確認できます。

2. ダウンロードする

Android Studioでは、オンラインである限り、パッケージを取得してプロジェクトに追加するための「パッケージ取得」ボタンが用意されています。

Visual Studioのコードを使用している場合は、pubspec.yamlファイルに変更を加えると、flutter packages getコマンドが自動的に起動します。

上記のIDEを使用していない場合は、コマンドラインからインストールすることができます。

$ flutter packages get

3. プロジェクトにインポートする

使用したいdartのコードに移動し、ファイルの先頭にインポートします。

import 'package:sqflite/sqflite.dart';

Quick Flutter SQFLite Database HowTo Snippets

1. データベースパスの取得方法

        // Check if we have an existing copy first
        var databasesPath = await getDatabasesPath();
        String path = join(databasesPath, "demo_asset_example.db");

2. データベースの開き方

        // try opening (will work if it exists)
        Database db;
        try {
          db = await openDatabase(path, readOnly: true);
        } catch (e) {
          print("Error $e");
        }

ヘルパークラスを入れることができます。

class Helper {
  final String path;
  Helper(this.path);
  Database _db;
  final _lock = Lock();

  Future<Database> getDb() async {
    if (_db == null) {
      await _lock.synchronized(() async {
        // Check again once entering the synchronized block
        if (_db == null) {
          _db = await openDatabase(path);
        }
      });
    }
    return _db;
  }

あるいは

  Future<Database> get db async {
    if (_db != null) return _db;
    _db = await initDb();
    return _db;
  }

これにより、initDb()は、私たちにパスを取得し、それを次のように開くカスタムメソッドです。

  initDb() async {
    io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "test.db");
    var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
    return theDb;
  }

3. データベーステーブルの作成方法

Sを使って、flutterでデータベーステーブルを作成する方法を見てみましょう。

      var db = await openDatabase(path);
      await db.execute("CREATE TABLE IF NOT EXISTS Test(id INTEGER PRIMARY KEY)");

または

  void _onCreate(Database db, int version) async {
    // When creating the db, create the table
    await db.execute(
        "CREATE TABLE Employee(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT, mobileno TEXT,emailId TEXT )");
    print("Created tables");
  }

dbデータベースオブジェクトです。このオブジェクトの execute()` メソッドを呼び出し、テーブルを作成するための生の sql 文を渡します。

4.データベースのテーブルに挿入する方法

      await db.insert("Test", {"id": 1});

または

  Future<int> insertTodo(Todo todo) async {
    Database db = await this.db;
    var result = await db.insert(tblTodo, todo.toMap());
    return result;
  }

例えば、PersonとそのプロパティをDatabaseに挿入して、挿入されたPersonを返したいとします。

  Future insertPerson(Person person) async {
    person.id = await _db.insert("people", person.toMap());
    return person;
    }

または

  Future insertPerson(Person person) async {
    person.id = await _db.insert("people", person.toMap());
    return person;
    }

5. SQLiteテーブルからのクエリまたはセレクトの方法

      await db.query("Test")

データベースからPeopleのリストをselectして返したいとします。

    Future fetchEveryone() async {
    List results = await _db.query("people", columns: Person.columns);
    List people = new List();
    results.forEach((map) {
      people.add(Person.fromMap(map));
    });
    return people;
    }

また、flutterでSQliteデータベースのリストを照会して、リストを生成したいとします。また、rawQueryメソッドを使って、生のクエリを使うこともできます。このメソッドには、実行されるSQL文を渡します。

  Future<List<Employee>> getEmployees() async {
    var dbClient = await db;
    List<Map> list = await dbClient.rawQuery('SELECT * FROM Employee');
    List<Employee> employees = new List();
    for (int i = 0; i < list.length; i++) {
      employees.add(new Employee(list[i]["firstname"], list[i]["lastname"], list[i]["mobileno"], list[i]["emailid"]));
    }
    print(employees.length);
    return employees;
  }

別の例もあります。

  Future<List> getTodos() async {
    Database db = await this.db;
    var result = await db.rawQuery("SELECT * FROM $tblTodo ORDER BY $colPriority ASC");
    return result;
  }

ユーザーがログインしているかどうかを調べたいとします。

  Future<bool> isLoggedIn() async {
    var dbClient = await db;
    var res = await dbClient.query("User");
    return res.length > 0 ? true : false;
  }

7 . SQLiteでアイテムの数をカウントする方法

  Future<int> getCount() async {
    Database db = await this.db;
    var result = Sqflite.firstIntValue(
      await db.rawQuery("SELECT COUNT (*) FROM $tblTodo")
    );
    return result;
  }

7. SQFLiteを使ってSQLiteデータベースのデータを更新する方法

  Future<int> updateTodo(Todo todo) async {
    var db = await this.db;
    var result = await db.update(tblTodo, todo.toMap(),
      where: "$colId = ?", whereArgs: [todo.id]);
    return result;
  }

7. SQFLite を使用した SQLite データベースからの削除方法

  Future<int> deleteTodo(int id) async {
    int result;
    var db = await this.db;
    result = await db.rawDelete('DELETE FROM $tblTodo WHERE $colId = $id');
    return result;
  }

または

  Future<int> deleteUsers() async {
    var dbClient = await db;
    int res = await dbClient.delete("User");
    return res;
  }

6. データベースを閉じるには

      await db.close();

または

  Future close() async {
    await _db.close();
  }

完全な例

それでは、Flutter SQFliteを使った完全な例を見てみましょう。

(a). フラッターSQFLite - INSERT,SELECT,SHOW

これはシンプルなDart Flutter Example Tutorialで、flutterアプリケーションで基本的なCRUD: Insert, Select, Showデータを実行する方法を示しています。ここでは、SQFLiteというSQLiteプラグインを使用します。これは、私たちのデータベースが SQLiteであるためです。

完全なサンプルプロジェクト

ここでは完全なソースコードを紹介します。

(a). pubspec.yaml

私たちの依存関係

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.2
  path_provider: '>=0.3.0'
  sqflite: any

dev_dependencies:
  flutter_test:
    sdk: flutter

(b). employee.dart

プロパティとしてfirstname, lastname, mobile number, emailを持つ1人の従業員を表現するdartクラスです。これらのプロパティはコンストラクタで受け取ります。

class Employee {
  String firstName;
  String lastName;
  String mobileNo;
  String emailId;

  Employee(this.firstName, this.lastName, this.mobileNo, this.emailId);
  Employee.fromMap(Map map) {
    firstName = map[firstName];
    lastName = map[lastName];
    mobileNo = map[mobileNo];
    emailId = map[emailId];
  }
}

(c). dbhelper.dart

データベース・クラッド操作の実装を支援する DBHelper クラスです。

import 'dart:async';
import 'dart:io' as io;
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_crud/model/employee.dart';

class DBHelper {
  static Database _db;

  Future<Database> get db async {
    if (_db != null) return _db;
    _db = await initDb();
    return _db;
  }

  initDb() async {
    io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "test.db");
    var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
    return theDb;
  }

  void _onCreate(Database db, int version) async {
    // When creating the db, create the table
    await db.execute(
        "CREATE TABLE Employee(id INTEGER PRIMARY KEY, firstname TEXT, lastname TEXT, mobileno TEXT,emailId TEXT )");
    print("Created tables");
  }

  void saveEmployee(Employee employee) async {
    var dbClient = await db;
    await dbClient.transaction((txn) async {
      return await txn.rawInsert(
          'INSERT INTO Employee(firstname, lastname, mobileno, emailid ) VALUES(' +
              ''' +
              employee.firstName +
              ''' +
              ',' +
              ''' +
              employee.lastName +
              ''' +
              ',' +
              ''' +
              employee.mobileNo +
              ''' +
              ',' +
              ''' +
              employee.emailId +
              ''' +
              ')');
    });
  }

  Future<List<Employee>> getEmployees() async {
    var dbClient = await db;
    List<Map> list = await dbClient.rawQuery('SELECT * FROM Employee');
    List<Employee> employees = new List();
    for (int i = 0; i < list.length; i++) {
      employees.add(new Employee(list[i]["firstname"], list[i]["lastname"], list[i]["mobileno"], list[i]["emailid"]));
    }
    print(employees.length);
    return employees;
  }
}

(d). emloyeelist.dart

このファイルでは、従業員のリストが非同期的に取得され、リストビューでレンダリングされます。

import 'package:flutter/material.dart';
import 'package:flutter_crud/model/employee.dart';
import 'dart:async';
import 'package:flutter_crud/database/dbhelper.dart';

Future<List<Employee>> fetchEmployeesFromDatabase() async {
  var dbHelper = DBHelper();
  Future<List<Employee>> employees = dbHelper.getEmployees();
  return employees;
}

class MyEmployeeList extends StatefulWidget {
  @override
  MyEmployeeListPageState createState() => new MyEmployeeListPageState();
}

class MyEmployeeListPageState extends State<MyEmployeeList> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Employee List'),
      ),
      body: new Container(
        padding: new EdgeInsets.all(16.0),
        child: new FutureBuilder<List<Employee>>(
          future: fetchEmployeesFromDatabase(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return new ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) {
                    return new Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          new Text(snapshot.data[index].firstName,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold, fontSize: 18.0)),
                          new Text(snapshot.data[index].lastName,
                              style: new TextStyle(
                                  fontWeight: FontWeight.bold, fontSize: 14.0)),
                          new Divider()
                        ]);
                  });
            } else if (snapshot.hasError) {
              return new Text("${snapshot.error}");
            }
            return new Container(alignment: AlignmentDirectional.center,child: new CircularProgressIndicator(),);
          },
        ),
      ),
    );
  }
}

(e). main.dart

mainクラスでは、mainメソッドを定義し、dartアプリケーションへの入り口としています。

import 'package:flutter/material.dart';
import 'package:flutter_crud/database/dbhelper.dart';
import 'package:flutter_crud/model/employee.dart';
import 'package:flutter_crud/employeelist.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'SQFLite DataBase Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

Employee employee = new Employee("", "", "", "");

String firstname;
String lastname;
String emailId;
String mobileno;
final scaffoldKey = new GlobalKey<ScaffoldState>();
final formKey = new GlobalKey<FormState>();

    @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(
        title: new Text('Saving Employee'),
        actions: <Widget>[
            new IconButton(
              icon: const Icon(Icons.view_list),
              tooltip: 'Next choice',
              onPressed: () {
              navigateToEmployeeList();
              },
            ),
          ]
      ),
      body: new Padding(
        padding: const EdgeInsets.all(16.0),
        child: new Form(
          key: formKey,
          child: new Column(
            children: [
              new TextFormField(
                keyboardType: TextInputType.text,
                decoration: new InputDecoration(labelText: 'First Name'),
                validator: (val) =>
                    val.length == 0 ?"Enter FirstName" : null,
                onSaved: (val) => this.firstname = val,
              ),
              new TextFormField(
                keyboardType: TextInputType.text,
                decoration: new InputDecoration(labelText: 'Last Name'),
                validator: (val) =>
                    val.length ==0 ? 'Enter LastName' : null,
                onSaved: (val) => this.lastname = val,
              ),
              new TextFormField(
                keyboardType: TextInputType.phone,
                decoration: new InputDecoration(labelText: 'Mobile No'),
                validator: (val) =>
                    val.length ==0 ? 'Enter Mobile No' : null,
                onSaved: (val) => this.mobileno = val,
              ),
              new TextFormField(
                keyboardType: TextInputType.emailAddress,
                decoration: new InputDecoration(labelText: 'Email Id'),
                validator: (val) =>
                    val.length ==0 ? 'Enter Email Id' : null,
                onSaved: (val) => this.emailId = val,
              ),
              new Container(margin: const EdgeInsets.only(top: 10.0),child: new RaisedButton(onPressed: _submit,
                child: new Text('Save Employee'),),)

            ],
          ),
        ),
      ),
    );
  }
  void _submit() {
     if (this.formKey.currentState.validate()) {
      formKey.currentState.save();
     }else{
       return null;
     }
    var employee = Employee(firstname,lastname,mobileno,emailId);
    var dbHelper = DBHelper();
    dbHelper.saveEmployee(employee);
    _showSnackBar("Data saved successfully");
  }

  void _showSnackBar(String text) {
    scaffoldKey.currentState
        .showSnackBar(new SnackBar(content: new Text(text)));
  }

  void navigateToEmployeeList(){
     Navigator.push(
    context,
    new MaterialPageRoute(builder: (context) => new MyEmployeeList()),
  );
  }
}

ダウンロード

それでは、プロジェクトをダウンロードするか、githubから閲覧してみましょう。

No. 場所 リンク
1. GitHub Direct Download
2. GitHub Browse

Credit and Thanks to the Original Creator of the above project @payen83

実行方法

  1. 上記プロジェクトをダウンロードします。
  2. 通常通り、android studio/visual studioでアプリケーションを作成します。
  3. pubspec.yaml を編集して、適切な依存関係を追加します。
    1. 上記のdartファイルをプロジェクトにコピーペーストします。

その後は

デバイスまたはエミュレータが起動していることを確認して、android studioの「実行」ボタンをクリックすると、自動的にデバイスが選択され、アプリがインストールされます。

ターミナルやコマンドプロンプトを使うこともできます。プロジェクトのルートページに移動して、次のように入力します。

flutter.bat build apk

これでAPKがビルドされるので、デバイスにドラッグしてインストールすることができます。私のマシンではビルドに約3分かかりましたが、これは悪くないと思います。

Categorized in: