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日
    浏览(43)
  • Redis的简单使用 (实现Session持久化)

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

    2024年02月11日
    浏览(43)
  • Docker数据持久化

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

    2024年01月23日
    浏览(60)
  • RabbitMQ-数据持久化

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

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

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

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

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

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

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

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

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

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

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

    2024年02月11日
    浏览(41)
  • 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日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包