[フラッター実際の戦闘]大量の複雑なデータの永続性

Lao Meng's Guide:前回の記事では、AndroidとiOSのファイルディレクトリシステムについて説明しました。この記事では、SQLiteを使用てデータ保存する方法について説明しました貢献は大歓迎ですhttp//laomengit.com/plan/Contribution.html

データをローカルに保存することは、次のシナリオなど、アプリケーションの非常に重要な機能の1つです。ニュースまたはブログアプリケーションを開いてからホームページにアクセスします。ローカルに保存されたデータがない場合は、データを返す前にネットワーク経由でデータを取得する必要があります。 、ユーザーには空白のページが表示され、ニュースの一部がローカルに保存されている場合、データのこの部分が表示され、最新のデータが返されたときに更新できます。ユーザーエクスペリエンスの場合、2番目のエクスペリエンスの方が明らかに優れています。

SQLiteは、現在最も人気のあるローカルストレージフレームワークの1つです。この記事では、SQLiteを使用してデータを保存、クエリ、および削除する方法を紹介します。

SQLiteパブアドレス:https//pub.flutter-io.cn/packages/sqflite

SQLite Github:https//github.com/tekartik/sqflite

SQLiteの説明:https//www.sqlitetutorial.net/

データベースとSQLステートメントについて少し知識がある場合は、次の説明がわかりやすくなります。データベースとSQLステートメントについて何も知らない場合は、次の説明が理解しにくい場合があります。

最初にデータベースとSQLステートメントについて学ぶ必要がありますか?必要ではないと思います。アプリケーションで使用されるデータベースとSQLステートメントに関連する知識は、データベースを開く、テーブルを作成する、SQLクエリステートメント、更新ステートメント、削除ステートメントなど、非常に基本的なものです。これらはすべて固定形式です。固定ステートメントを覚えておいてください。 OK。

依存関係を追加する

SQLiteは、システムにFlutterが付属しているのではなく、pubspec.yaml依存関係ファイルを追加するためのサードパーティのプラグインプロジェクトです。

dependencies:
  sqflite: ^1.3.1
  path_provider: ^1.6.11

注文の実行:

flutter pub get

SQLiteを使用してデータベースを作成する場合、パラメーターとしてローカルパスが必要になるため、path_providerプラグインを追加してローカルパスを取得します。

SQLiteアクセスを作成するためのシングルトンモード

SQLiteの使用は、必ずしもシングルトンモードを使用するわけではありません。シングルトンモードは、アプリケーション全体が1つのデータベースインスタンスとグローバルアクセスのみを持つようにするためのものです。

class DBProvider{

  static final DBProvider _singleton = DBProvider._internal();

  factory DBProvider() {
    return _singleton;
  }

  DBProvider._internal();
}

データベースを初期化します

import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';

class DBProvider {
  static final DBProvider _singleton = DBProvider._internal();

  factory DBProvider() {
    return _singleton;
  }

  DBProvider._internal();

  static Database _db;

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

  Future<Database> _initDB() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, 'dbName');
    return await openDatabase(path,
        version: 1, onCreate: _onCreate, onUpgrade: _onUpgrade);
  }

  ///
  /// 创建Table
  ///
  Future _onCreate(Database db, int version) async {}

  ///
  /// 更新Table
  ///
  Future _onUpgrade(Database db, int oldVersion, int newVersion) async {}
}

テーブルの作成、テーブルはテーブルを表し、下にユーザーテーブルを作成します。テーブルの列には、ID(一意の識別子)、名前(名前)、年齢(年齢)、性別(性別)があります。

///
/// 创建Table
///
Future _onCreate(Database db, int version) async {
  return await db.execute("CREATE TABLE User ("
      "id integer primary key AUTOINCREMENT,"
      "name TEXT,"
      "age TEXT,"
      "sex integer"
      ")");
}

データを保存する

まず、データストレージ用のユーザーモデルクラスを作成します。

class User {
  int id;
  String name;
  int age;
  int sex;

  User({this.id, this.name, this.age, this.sex});

  User.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    name = json['name'];
    age = json['age'];
    sex = json['sex'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    data['name'] = this.name;
    data['age'] = this.age;
    data['sex'] = this.sex;
    return data;
  }
}

データの保存:

Future saveData(User user) async {
  var _db = await db;
  return await _db.insert('User', user.toJson());
}

ケース:名前、年齢、性別を入力し、[保存]をクリックします

class _AddUser extends StatefulWidget {
  @override
  __AddUserState createState() => __AddUserState();
}

class __AddUserState extends State<_AddUser> {
  String _radioGroupValue = '0';
  TextEditingController _nameController;
  TextEditingController _ageController;

  @override
  void initState() {
    super.initState();
    _nameController = TextEditingController();
    _ageController = TextEditingController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('保存数据'),
      ),
      body: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              Text('姓名:'),
              Flexible(
                child: TextField(
                  controller: _nameController,
                ),
              ),
            ],
          ),
          Row(
            children: <Widget>[
              Text('年龄:'),
              Flexible(
                child: TextField(
                  controller: _ageController,
                ),
              ),
            ],
          ),
          Row(
            children: <Widget>[
              Text('性别:'),
              Flexible(
                child: RadioListTile(
                  title: Text('男'),
                  value: '0',
                  groupValue: _radioGroupValue,
                  onChanged: (value) {
                    setState(() {
                      _radioGroupValue = value;
                    });
                  },
                ),
              ),
              Flexible(
                child: RadioListTile(
                  title: Text('女'),
                  value: '1',
                  groupValue: _radioGroupValue,
                  onChanged: (value) {
                    setState(() {
                      _radioGroupValue = value;
                    });
                  },
                ),
              ),
            ],
          ),
          Builder(
            builder: (context) {
              return RaisedButton(
                child: Text('保存'),
                onPressed: () async {
                  var user = User(
                      name: '${_nameController.text}',
                      age: int.parse('${_ageController.text}'),
                      sex: int.parse('$_radioGroupValue'));

                  int result = await DBProvider().saveData(user);
                  if (result > 0) {
                    Scaffold.of(context).showSnackBar(SnackBar(
                      content: Text('保存数据成功,result:$result'),
                    ));
                  } else {
                    Scaffold.of(context).showSnackBar(SnackBar(
                      content: Text('保存数据失败,result:$result'),
                    ));
                  }
                },
              );
            },
          )
        ],
      ),
    );
  }
}

SQLステートメントを使用してデータを保存します。

Future rawInsert(User user) async {
  var _db = await db;
  return await _db.rawInsert(
      'INSERT Into User (name,age,sex) VALUES (?,?,?)',[user.name,user.age,user.sex]);
}

クエリデータ

すべてのデータを照会します。

Future<List<User>> findAll() async {
    var _db = await db;
    List<Map<String, dynamic>> result = await _db.query('User');

    return result.isNotEmpty ? result.map((e) {
      return User.fromJson(e);
    }).toList():[];
  }

クエリされたデータをテーブルに表示します。

class DatabaseDemo extends StatefulWidget {
  @override
  _DatabaseDemoState createState() => _DatabaseDemoState();
}

class _DatabaseDemoState extends State<DatabaseDemo> {
  List<User> _list = [];

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  _loadData() async {
    _list = await DBProvider().findAll();
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Sqlite Demo'),
      ),
      body: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              RaisedButton(
                child: Text('查询数据'),
                onPressed: (){
                  _loadData();
                },
              ),
              RaisedButton(
                child: Text('添加数据'),
                onPressed: (){
                  Navigator.of(context).push(MaterialPageRoute(builder: (context){
                    return _AddUser();
                  }));
                },
              ),
            ],
          ),
          Table(
            children: [
              TableRow(children: [
                TableCell(child: Text('id')),
                TableCell(child: Text('姓名')),
                TableCell(child: Text('年龄')),
                TableCell(child: Text('性别')),
              ]),
              ..._list.map((user) {
                return TableRow(children: [
                  TableCell(child: Text('${user.id}')),
                  TableCell(child: Text('${user.name}')),
                  TableCell(child: Text('${user.age}')),
                  TableCell(child: Text(user.sex == 0 ? '男' : '女')),
                ]);
              }).toList()
            ],
          )
        ],
      ),
    );
  }
}

12歳のデータのクエリなど、条件に従ってクエリを実行します。

Future<List<User>> find(int age) async {
    var _db = await db;
    List<Map<String, dynamic>> result =
        await _db.query('User', where: 'age = ?', whereArgs: [age]);

    return result.isNotEmpty ? result.map((e) {
      return User.fromJson(e);
    }).toList():[];
  }

使用する:

_loadData() async {
  _list = await DBProvider().find(12);
  setState(() {});
}

データの更新

ユーザーIDに従ってデータを更新します。

Future<int> update(User user) async {
  var _db = await db;
  return await _db
      .update('User', user.toJson(), where: 'id = ?', whereArgs: [user.id]);
}

データを変更するには、ページにジャンプします。

RaisedButton(
  child: Text('修改第一行数据'),
  onPressed: () {
    if (_list.length > 1) {
      Navigator.of(context)
          .push(MaterialPageRoute(builder: (context) {
        return _AddUser(
          user: _list[0],
        );
      }));
    }
  },
),

変更したデータを保存します。

RaisedButton(
  child: Text('保存'),
  onPressed: () async {
    var user = User(
        name: '${_nameController.text}',
        age: int.parse('${_ageController.text}'),
        sex: int.parse('$_radioGroupValue'));
    if (widget.user == null) {
      _saveData(context,user);
    } else {
      _updateData(context,user);
    }
  },
)

_updateData(BuildContext context,User user) async {
    user.id = widget.user.id;
    int result = await DBProvider().update(user);
    if (result > 0) {
      Scaffold.of(context).showSnackBar(SnackBar(
        content: Text('修改数据成功,result:$result'),
      ));
    } else {
      Scaffold.of(context).showSnackBar(SnackBar(
        content: Text('修改数据失败,result:$result'),
      ));
    }
  }

データを削除する

IDに基づいて適格なデータを削除します。

Future<int> delete(int id) async {
  var _db = await db;
  return await _db.delete('User', where: 'id = ?', whereArgs: [id]);
}

データの最初の行を削除し、削除が成功した後にデータを更新します。

RaisedButton(
  child: Text('删除第一行数据'),
  onPressed: () async {
    if (_list.length > 0) {
      await DBProvider().delete(_list[0].id);
      _loadData();
    }
  },
),

すべてのデータを削除します。

Future<int> deleteAll() async {
  var _db = await db;
  return await _db.delete('User');
}

総括する

SQLiteの基本的な使用法を紹介しました。データの追加、削除、変更、クエリが最も頻繁に使用されます。SQLiteには、グループ化や共同クエリなど、あまり使用されない高度なクエリステートメントもいくつかあります。

SQLiteが正常に作成されると、db_name.dbファイルがローカルに作成されます。ファイルディレクトリは、データベースが初期化されたときに設定されたディレクトリです。

と通信する

と通信する

Laomeng Flutterブログ(330コントロールの使用法+実際の戦闘紹介シリーズ):http//laomengit.com

Flutter交換グループ(WeChat:laomengit)に参加し、パブリックアカウント[Lao Meng Flutter]をフォローすることを歓迎します:

おすすめ

転載: blog.csdn.net/mengks1987/article/details/108782226