flutter:数据持久化

这篇具有很好参考价值的文章主要介绍了flutter:数据持久化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简单的数据持久化

保存数据到本地磁盘是应用程序常用功能之一,比如保存用户登录信息、用户配置信息等。而保存这些信息通常使用 shared_preferences,它保存数据的形式为 Key-Value(键值对),支持 Android 和 iOS。shared_preferences 是一个第三方插件,在 Android 中使用 SharedPreferences,在 iOS中使用 NSUserDefaults

shared_preferences 持久化保存数据,但在一下情况下会删除数据:

  • 卸载应用程序。
  • 在设置中清除应用数据。

安装

添加依赖

在项目的 pubspec.yaml 文件中添加依赖

dependencies:
  shared_preferences: ^2.1.1

安装

flutter pub get

安装成功后可以在pubspec.lock文件中找到对应的设置

保存/读取数据

shared_preferences 支持的数据类型有 intdoubleboolstringstringList

int类型

// 初始化
var prefs = await SharedPreferences.getInstance();
// 存储
prefs.setInt('key_int', 20);
// 读取
var res = prefs.getInt('key_int');
print("数据是$res");

flutter:数据持久化
其他类型的操作调用对应的方法即可

在这里遇到了个问题

提示[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: PlatformException(channel-error, Unable to establish connection on channel., null, null)

查了好久最后发现是sdk版本的问题,下载了一个Android 9就解决了。
flutter:数据持久化

删除数据

删除指定的key

Future<bool> _deleteData() async {
  var prefs = await SharedPreferences.getInstance();
  prefs.remove('Key');
}

清除所有数据(谨慎使用)

Future<bool> _deleteData() async {
  var prefs = await SharedPreferences.getInstance();
  prefs.remove('Key');
}

key相关操作

获取所有key

Future<Set<String>> _getKeys() async {
  var prefs = await SharedPreferences.getInstance();
  var keys = prefs.getKeys();
  return keys ?? [];
}

检测key是否存在

Future<bool> _containsKey() async {
  var prefs = await SharedPreferences.getInstance();
  return prefs.containsKey('Key') ?? false;
}

大量复杂数据持久化

SharedPreferences只能存储少量简单的数据,如果需要存储大量并且复杂的数据可以使用SQLite

Flutter中的SQLite是一个轻量级的本地数据库,它可以在移动应用程序中存储和管理数据。SQLite是一种关系型数据库管理系统,它使用SQL语言进行数据操作。在Flutter中,可以使用sqflite插件来访问SQLite数据库。该插件提供了一组API,可以执行SQL查询、插入、更新和删除操作。使用SQLite可以在应用程序中存储和管理大量数据,例如用户信息、设置、日志等。SQLite还可以在离线模式下使用,这使得应用程序可以在没有网络连接的情况下继续工作。

flutter:数据持久化

安装

添加依赖

dependencies:
  sqflite: ^2.0.1
  path_provider: ^2.0.11

使用 SQLite 创建数据库的时候需要本地路径做为参数,所以添加path_provider 插件获取本地路径。sqflite的版本过高则需要对应的dart sdk版本

安装

flutter pub get

单例模式创建SQLite 访问

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

下面是一个简单的新增、删除、查询全部的操作,SQLite的其他操作可以自行百度

数据库操作

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

// 单例模式创建 SQLite 访问
class DBProvider {
  // 创建一个实例
  static final DBProvider _singleton = DBProvider._internal();

  factory DBProvider() {
    return _singleton;
  }
  // 命名构造函数,因为_internal是私有的,因此只有_singleton和DBProvider()可以被外部调用,这样保证了只会有一个类的实例存在
  DBProvider._internal();

//  数据库对象
  static Database? _db;
  // 获取数据库对象,Future表示异步操作类型
  Future<Database?> get db async {
    if (_db != null) {
      return _db;
    }
    // 初始化数据库
    _db = await _initDB();
    return _db;
  }

// 初始化数据库
  Future<Database> _initDB() async {
    // 获取应用程序文档目录
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    // 使用join函数拼接路径
    String path = '${documentsDirectory.path}dbName';
    return await openDatabase(path,
        version: 1, onCreate: _onCreate, onUpgrade: _onUpgrade);
  }

// 创建表
  Future _onCreate(Database db, int version) async {
    //  创建一张用户表,表列有 id(唯一标识)、name(姓名)、age(年龄)、sex(性别)
    // execute参数是sql语句
    return await db.execute("CREATE TABLE User ("
        "id integer primary key AUTOINCREMENT,"
        "name TEXT,"
        "age TEXT,"
        "sex integer"
        ")");
  }

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

//  新增数据
  Future saveDate(User user) async {
    // 这里是异步操作,确保能拿到db
    var db = await this.db;
    // 表名,一个map对象
    return await db?.insert('User', user.toJson());
  }

//  根据id删除数据
  Future delete(int id) async {
    var db = await this.db;
    return db?.delete('User', where: 'id=?', whereArgs: [id]);
  }

//  查询所有数据
  Future findAll() async {
    var db = await this.db;
    List<Map<String, Object?>>? result = await db?.query('User');
    if (result != null && result.isNotEmpty) {
      return result.map((e) {
        return User.fromJson(e);
      }).toList();
    }
    return [];
  }
}

// 创建一个User的Model类,用于数据的保存
class User {
  late int id;
  late String name;
  late int age;
  late int sex;

//  构造函数
  User(
      {required this.id,
      required this.name,
      required this.age,
      required this.sex});

// 将JSON对象转为User对象(命名构造函数)
  User.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    name = json['name'];
    age = int.parse(json['age']);
    sex = json['sex'];
  }

//  将User对象转为JSON对象
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    // 在函数中因为没有id变量,所以这里的id代表的类的成员变量;如果函数中有id,那么必须使用this.id来区分是函数内的变量还是类的成员变量
    data['id'] = id;
    data['name'] = name;
    data['age'] = age;
    data['sex'] = sex;
    return data;
  }
}

功能页面

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'db/db_provider.dart';

//使用箭头函数简写
main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  //创建widget的唯一标识
  const MyApp({Key? key}) : super(key: key);

  //重写build方法
  
  Widget build(BuildContext context) {
    //返回一个material类型的app
    return const MaterialApp(
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('zh', 'CN'),
        Locale('en', 'US'),
      ],
      //指定显示哪一个页面
      home: YcHomePage(),
    );
  }
}

//app的主页面
class YcHomePage extends StatelessWidget {
  const YcHomePage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('数据持久化'),
      ),
      body: const YcHomeBody(),
    );
  }
}

class YcHomeBody extends StatefulWidget {
  const YcHomeBody({Key? key}) : super(key: key);
  
  State<YcHomeBody> createState() => _YcHomeBodyState();
}

class _YcHomeBodyState extends State<YcHomeBody> {
  // 表格数据
  List<User> _list = [];
  final List<String> _nameList = [
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j'
  ];

  // 加在数据的方法
  _loadData() async {
    _list = await DBProvider().findAll();
    setState(() {});
  }

  
  void initState() {
    // 初始化状态
    super.initState();
    _loadData();
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 顶部操作按钮
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ElevatedButton(
                onPressed: () async {
                  User user = User(
                      id: DateTime.now().microsecondsSinceEpoch,
                      name: _nameList[_list.length],
                      age: Random().nextInt(11) + 10,
                      sex: Random().nextInt(2));
                  int res = await DBProvider().saveDate(user);
                  if (res > 0) {
                    print("新增成功:$res");
                    // 刷新数据
                    _loadData();
                  } else {
                    print("新增失败:$res");
                  }
                },
                child: const Text("新增一条数据")),
            ElevatedButton(
                onPressed: () async {
                  if (_list.isNotEmpty) {
                    await DBProvider().delete(_list[0].id);
                    _loadData();
                  }
                },
                child: const Text("删除第一条数据"))
          ],
        ),
        //占位
        const SizedBox(
          height: 20,
        ),
        // 底部表格
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Table(
              border: TableBorder.all(
                width: 1,
                color: Colors.grey,
                style: BorderStyle.solid,
              ),
              columnWidths: const {
                0: FixedColumnWidth(100),
                1: FixedColumnWidth(100),
                2: FixedColumnWidth(100),
                3: FixedColumnWidth(100)
              },
              children: [
                const TableRow(children: [
                  TableCell(
                      child: Text(
                    'id',
                    textAlign: TextAlign.center,
                  )),
                  TableCell(child: Text('姓名', textAlign: TextAlign.center)),
                  TableCell(child: Text('年龄', textAlign: TextAlign.center)),
                  TableCell(child: Text('性别', textAlign: TextAlign.center)),
                ]),
                ..._list.map((user) {
                  return TableRow(children: [
                    TableCell(
                        child: Text('${user.id}', textAlign: TextAlign.center)),
                    TableCell(
                        child: Text(user.name, textAlign: TextAlign.center)),
                    TableCell(
                        child:
                            Text('${user.age}', textAlign: TextAlign.center)),
                    TableCell(
                        child: Text(user.sex == 0 ? '男' : '女',
                            textAlign: TextAlign.center)),
                  ]);
                }).toList()
              ],
            )
          ],
        )
      ],
    );
  }
}

flutter:数据持久化

优化

正常请求创建数据库与表的相关操作需要分离,这样便于维护。下面是一个例子

创建数据库

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

// 单例模式创建 SQLite 访问
class DatabaseHelper {
//   定义一个实例
  static final DatabaseHelper _instance = DatabaseHelper.internal();
  //使用Flutter的工厂构造函数语法来创建一个单例对象。确保只有一个DatabaseHelper对象存在,并且可以在整个应用程序中共享该对象
  factory DatabaseHelper() => _instance;

  // 创建一个数据库实例
  static Database? _database;
// 获取数据库实例
  Future<Database?> get database async {
    if (_database == null) {
      _database = await initDatabase();
    }
    return _database;
  }

  // 私有的命名构造函数,防止在类外部直接实例化
  DatabaseHelper.internal();

// 初始化数据库
  Future<Database> initDatabase() async {
    String databasesPath = await getDatabasesPath();
    String path = join(databasesPath, 'my_database.db');
    //   打开或创建表
    Database database = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute('CREATE TABLE IF NOT EXISTS search_history ('
          'id INTEGER PRIMARY KEY AUTOINCREMENT,' // 主键
          'name VARCHAR(50),' // 搜索的关键字
          'type VARCHAR(50),' // 搜索的类型
          'gmtCreate DATETIME' // 创建时间
          ')');
      //  创建其他表
    });
    return database;
  }
}

使用,操作数据

import 'package:sqflite/sqflite.dart';
import 'package:spider/store/database_helper.dart';
import 'package:spider/models/SearchHistoryModel.dart';

/**
 * 搜索历史持久化操作方法
 */

class HistoryStore {
  //  保存搜索历史
  Future<int> saveData(SearchHistoryModel historyModel) async {
    //   获取数据库对象
    Database database = await DatabaseHelper().database as Database;
    var existingData = await findByName(historyModel.name!);

    if (existingData == null) {
      return await database.insert('search_history', historyModel.toJson());
    }
    return 0;
  }

  // 查询所有的搜索历史
  Future<List<SearchHistoryModel>> findAll() async {
    Database database = await DatabaseHelper().database as Database;
    List result = await database.query('search_history');
    if (result.isNotEmpty) {
      return result.map((e) {
        return SearchHistoryModel.fromJson(e);
      }).toList();
    }
    return [];
  }

//  根据名字查询搜索历史
  Future findByName(String name) async {
    Database database = await DatabaseHelper().database as Database;
    List result = await database.query('search_history',
        where: 'name = ?', whereArgs: [name], limit: 1);
    if (result.isNotEmpty) {
      return result.first;
    }
    return null;
  }

//  删除所有搜索历史
  Future deleteAll() async {
    Database database = await DatabaseHelper().database as Database;
    await database.delete('search_history');
  }
}

补充

查看数据库数据
flutter:数据持久化
db文件一般在data/data/应用包名/databases路径下
flutter:数据持久化
右键保存到本地。然后使用数据库查看工具进行打开,我使用的是DBeaver,就依次为例
1、点击数据库选择新建数据库链接
2、选择sqlite数据库
flutter:数据持久化
3、打开导出的db文件

下面就可以正常查看数据了
flutter:数据持久化文章来源地址https://www.toymoban.com/news/detail-486138.html

到了这里,关于flutter:数据持久化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序上传头像和昵称持久化保存

    因为通过微信头像昵称填写功能获取到头像是一个临时头像,这个url只能一段时间内在微信访问,并且无法在公网访问这个url。所以非常有必要把这个url转成我么实际可用的头像到数据库中。让头像持久化的在微信和公网任何位置都能访问。 这里我们使用url转base64字符串的方

    2024年02月12日
    浏览(29)
  • Redis的简单使用 (实现Session持久化)

    🎉🎉🎉 点进来你就是我的人了 博主主页: 🙈🙈🙈 戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔 🤺🤺🤺 目录 一、Redis数据类型的使用 1. 字符串(String) 2. 字典类型(哈希 Hashes) 3. 列表(Lists) 4. 集合(Sets) 5. 有序集合(Sorted sets) 二、SpringBoot连接Redis操

    2024年02月11日
    浏览(33)
  • RabbitMQ-数据持久化

    1、交换机持久化(SpringAMQP默认) 2、队列持久化(SpringAMQP默认) 3、消息持久化         如果采用纯内存操作,那么消息存储达到队列的上限之后,会有一个page out操作,这个操作是将队列中已经有的一部分MQ消息转移到磁盘,给队列腾出空间,使得队列能够继续接收MQ消息

    2024年01月21日
    浏览(31)
  • Docker数据持久化

    在容器层的 UnionFS(联合文件系统)中对文件/目录的任何修改,无论是手工修改还是 容器在运行过程中的修改,在该容器丢失或被删除后这些修改将全部丢失。即这些修改是无 法保存下来的。若要保存下来这些修改,通常有两种方式: 定制镜像持久化:将这个修改过的容器

    2024年01月23日
    浏览(49)
  • Docker容器数据持久化

    Docker容器数据卷:volumes        数据卷是经过特殊设计的目录,可以绕过联合文件系统,为一个或者多个容器提供访问,数据卷设计的目的,在于数据的永久存储,它完全独立于容器的生存周期,因此,docker不会在容器删除时删除其挂载的数据卷,也不会存在类似的垃圾收集

    2024年02月10日
    浏览(41)
  • 【2023】Redis数据持久化

    Redis是基于内存的NoSQL数据库,读写速度很快,但是存储在内存中的Redis数据会在服务器重启后丢失。 然而在一些场景中,需要长久的保存数据,所以需要把内存中的数据持久化的保存在硬盘中。 Redis持久化提供两种方式: 1️⃣:AOF(Append Only File)只追加文件 2️⃣:RDB(

    2024年02月10日
    浏览(35)
  • redis数据安全(一)数据持久化

     一、Redis数据安全措施: 1、将数据持久化至硬盘 2、将数据复制至其他机器; 复制是在数据持久化的基础上进行的。 二、将数据持久化至硬盘 1、介绍:Redis是一个基于内存的数据库,它的数据是存放在内存中,内存有个问题就是关闭服务或者断电会丢失。Redis的数据也支持

    2024年01月20日
    浏览(27)
  • Docker啥是数据持久化?

    ​ 在容器层的 UnionFS(联合文件系统)中对文件/目录的任何修改,无论是手工修改还是容器在运行过程中的修改,在该容器丢失或被删除后这些修改将全部丢失。即这些修改是无法保存下来的。若要保存下来这些修改,通常有两种方式: 定制镜像持久化:将这个修改过的容

    2024年02月15日
    浏览(30)
  • Docker 数据持久化方案详解

    目录 一、Docker数据持久化概述 1.1联合文件系统 1.2容器的数据卷 1.2.1 什么是数据卷 1.2.2 数据卷特点 1.2.3 Docker提供三种方式将数据从宿主机挂载到容器 二、 Docker持久化方案 2.1 查看volume 基本命令使用方法 2.2 volume持久化方案 2.2.1volume简介 2.2.2.volume特点 2.2.3 挂载指定volume 2.

    2024年02月07日
    浏览(38)
  • Redis 7 教程 数据持久化

            RDB 持久化以指定的时间间隔执行数据集的时间点快照 。         把某一时刻的数据和状态以文件的形式写到磁盘上,即使出现故障宕机,快照文件也不会丢失,数据的可靠性得到保证。快照文件就是RDB(Redis DataBase)文件(dump.rdb)          在指定的时间间隔内将

    2024年02月11日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包