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");

在这里插入图片描述
其他类型的操作调用对应的方法即可

在这里遇到了个问题

提示[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就解决了。
在这里插入图片描述

删除数据

删除指定的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还可以在离线模式下使用,这使得应用程序可以在没有网络连接的情况下继续工作。

在这里插入图片描述

安装

添加依赖

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/29990.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

访问者模式(十八)

相信自己&#xff0c;请一定要相信自己 上一章简单介绍了命令模式(十七), 如果没有看过, 请观看上一章 一. 访问者模式 引用 菜鸟教程里面访问者模式介绍: https://www.runoob.com/design-pattern/visitor-pattern.html 在访问者模式&#xff08;Visitor Pattern&#xff09…

K8s in Action 阅读笔记——【14】Securing cluster nodes and the network

K8s in Action 阅读笔记——【14】Securing cluster nodes and the network 迄今为止&#xff0c;创建了 Pod 而不考虑它们允许消耗多少 CPU 和内存。但是&#xff0c;正如将在本章中看到的那样&#xff0c;设置 Pod 预期消耗和允许消耗的最大数量是任何 Pod 定义的重要部分。…

基于Flask+Bootstrap+机器学习的世界杯比赛预测系统

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

南京贸易企业增值税居高不下,该如何解决?

南京贸易企业增值税居高不下&#xff0c;该如何解决&#xff1f; 《税筹顾问》专注于园区招商&#xff0c;您的贴身节税小能手&#xff0c;合理合规节税&#xff01; 南京作为省会城市&#xff0c;近年来由于芯片、生物医药等产业的发展而跻身前十&#xff0c;随着它在教育、军…

C语言基础 位域

C语言基础&#xff1a;位域 主题&#xff1a;位域&#xff08;bit-field&#xff09; 关键字&#xff1a;位域 冒号 结构体 存储空间 参考链接&#xff1a;C语言中文网&#xff1a;位域 、C菜鸟工具&#xff08;在线编译器&#xff09;、位域知乎问答 注&#xff1a;以下内容中…

redis五种数据类型具体时候的底层编码

redis随着值的类型不同&#xff0c;其在底层编码类型会不相同。目前现有的编码格式有 #define OBJ_ENCODING_RAW 0 /* Raw representation */ #define OBJ_ENCODING_INT 1 /* Encoded as integer */ #define OBJ_ENCODING_HT 2 /* Encoded as hash table */ #def…

2023年打印机电商市场数据分析

近年来&#xff0c;伴随自动化办公及在线教育等场景的常态化&#xff0c;文件或学习资料等的打印需求不断增长&#xff0c;这也使得打印机需求暴增&#xff0c;打印机市场的市场规模也越来越大。 根据鲸参谋电商平台的相关数据显示&#xff0c;今年1月份至4月份&#xff0c;打印…

Unity UGUI1——基础组件概述

一、UGUI 介绍 ​ UGUI 是 Unity 引擎内自带的 UI 系统&#xff0c;官方称之为&#xff1a;Unity UI ​ 是目前 Unity 商业游戏开发中使用最广泛的 UI 系统开发解决方案 ​ 它是基于 Unity 游戏对象的 UI 系统&#xff0c;只能用来做游戏 UI 功能 ​ 不能用于开发 Unity 编…

简单的TCP网络程序·单进程(后端服务器)

目录 文件1&#xff1a;tcpServer.cc 文件2&#xff1a;tcpServer.hpp 1.提出日志概念 -- 在后续完善 日志格式 -- 暂定简单的打印功能 2.创建套接字 SOCK_STREAM -- socket参数 3.bind自己的套接字 4.设置socket 为监听状态 * 新接口1&#xff1a;listen 函数1&…

linux服务器上,docker安装nginx

如果出现 Using default tag: latest Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/images/create?fromImagenginx&taglatest": dial unix /va…

Python 中常用的数据类型及相关操作详解

文章目录 列表&#xff08;Lists&#xff09;创建列表访问列表元素添加元素到列表删除列表元素切片&#xff08;Slicing&#xff09;其他常用操作 元组&#xff08;Tuples&#xff09;创建元组访问元组元素元组长度其他常用操作 字符串&#xff08;Strings&#xff09;创建字符…

Three.js--》实现图片转3D效果展示

目录 项目搭建 初始化three.js基础代码 加载图片纹理 设置着色器 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 项目搭建 本案例还是借助框架书写th…

【Qt】Ubuntu安装GCC9.3.0版本的Qt5.15.5

目录 一、安装GCC9.3.0 1.下载GCC9.3.0源码 2.获取依赖项的包 3.生成Makefile文件 4.编译并安装 5.生成软链接 6. 查看GCC版本 二、安装Qt 1.下载Qt安装包 2.创建Qt项目并运行 一、安装GCC9.3.0 1.下载GCC9.3.0源码 https://ftp.gnu.org/gnu/gcc/gcc-9.3.0/gcc-9.3…

excel爬虫相关学习1:简单的excel爬虫

目录 1 什么是excel 爬虫 2 EXCEL爬虫 2.1 excel 爬虫的入口 2.2 需要配置的信息 2.2.1 如何获得 ua信息 2.3 获取的信息 2.3.1 获取信息的基本内容 2.3.2 获取过程 2.3.3 我们只用关注“表视图 ” 即可 2.4 EXCEL获得的爬虫数据 加载到excel里 2.5 数据到了excel表后…

Three.js--》实现3d汽车模型展览搭建

目录 项目搭建 初始化three.js基础代码 添加汽车模型展示 动态修改汽车模型 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 项目搭建 本案例还是借助…

flink主要组件及高可用配置

背景 flink不论运行在哪种环境&#xff0c;例如Yarn&#xff0c;Mesos&#xff0c;Kebernute以及独立集群&#xff0c;每个应用都会包含重要的几个组件&#xff0c;本文就来讲述下flink的主要组件以及如何实现flink的高可用配置 flink主要组件 如图所示&#xff0c;flink主要…

Java实训日志02

文章目录 八、项目开发实现步骤&#xff08;二&#xff09;创建项目1、创建Java项目2、创建目录&#xff0c;添加素材&#xff08;1&#xff09;创建help目录添加帮助文档&#xff08;2&#xff09;创建images目录添加图像素材&#xff08;3&#xff09;创建lib目录添加数据库驱…

Dockerfile创建镜像

一、Docker镜像的创建 创建镜像有三种方法&#xff0c;分别为【基于已有镜像创建】、【基于本地模板创建】以及【基于Dockerfile创建】。 1.1 基于现有镜像创建 &#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改docker run -it centos:7 /bin/bash …

设计模式之工厂方法模式笔记

设计模式之工厂方法模式笔记 说明Factory Method(工厂方法)目录UML抽象工厂示例类图咖啡抽象类美式咖啡类拿铁咖啡类 咖啡工厂接口美式咖啡工厂类拿铁咖啡工厂类 咖啡店类测试类 说明 记录下学习设计模式-工厂方法模式的写法。 Factory Method(工厂方法) 意图:定义一个用于创…

主从架构lua脚本-Redis(四)

上篇文章介绍了rdb、aof持久化。 持久化RDB/AOF-Redis&#xff08;三&#xff09;https://blog.csdn.net/ke1ying/article/details/131148269 redis数据备份策略 写job每小时copy一份到其他目录。目录里可以保留最近一个月数据。把目录日志保存到其他服务器&#xff0c;防止机…