【Flutter 实战】大量复杂数据持久化

【Flutter 实战】大量复杂数据持久化,第1张

概述老孟导读:上一篇文章讲解了 Android 和 iOS 的文件目录系统,此篇文章讲解如何使用 SQLite 保存数据。 欢迎大家投稿:http://laomengit.com/plan/Contrib

老孟导读:上一篇文章讲解了 AndroID 和 iOS 的文件目录系统,此篇文章讲解如何使用 sqlite 保存数据。
欢迎大家投稿:http://laomengit.com/plan/Contribution.html

保存数据到本地是应用程序非常重要的功能之一,比如如下场景:一个新闻类或者博客类的应用程序,打开后进入首页,如果本地没有保存数据,则需要通过网络获取数据,在返回数据之前,用户看到的是空白页面,而如果本地保存了部分新闻,则显示这部分数据,等待最新的数据返回时在刷新即可,对用户体验来说,明显第二种体验更佳。

sqlite 是目前最受欢迎的本地存储框架之一,此篇文章将会介绍如何使用 sqlite 保存、查询、删除数据等。

sqlite pub地址:https://pub.flutter-io.cn/packages/sqflite

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

sqlite 讲解:https://www.sqlitetutorial.net/

如果您对数据库和 sql 语句相关知识有一点了解,下面的讲解会比较容易理解,如果对数据库和 sql 语句相关知识一点不了解,那下面的讲解理解起来可能会有一定的难度。

那是否需要先去学习数据库和 sql 语句相关知识?我觉得没有必要,应用程序使用的数据库和 sql 语句相关知识都是非常基础的,比如打开数据库、创建表、sql 查询语句、更新语句、删除语句等,这些都是固定的格式,固定语句记住即可。

添加依赖

sqlite 并不是 Flutter 系统自带的,而是一个第三方插件,在项目的 pubspec.yaml 文件中添加依赖:

dependencIEs:  sqflite: ^1.3.1  path_provIDer: ^1.6.11

执行命令:

Flutter pub get

使用 sqlite 创建数据库的时候需要本地路径做为参数,所以添加path_provIDer 插件获取本地路径。

单例模式创建 sqlite 访问

使用 sqlite 并不是一定要使用单例模式,单例模式是为了保证整个应用程序仅有一个数据库实例和全局访问。

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 {}}

创建 table,table 代表一张表,下面创建一张用户表,表列有 ID(唯一标识)、name(姓名)、age(年龄)、sex(性别)。

////// 创建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"      ")");}
保存数据

先创建一个 User 的 Model 类,用于数据的保存:

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',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(() {});}

更新数据

根据 User 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}',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',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 的文件,文件的目录就是初始化数据库时设置的目录。

交流交流

老孟Flutter博客(330个控件用法+实战入门系列文章):http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

总结

以上是内存溢出为你收集整理的【Flutter 实战】大量复杂数据持久化全部内容,希望文章能够帮你解决【Flutter 实战】大量复杂数据持久化所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1000438.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存