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.1path_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 {// 这里是异步操作,确保能拿到dbvar 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类型的appreturn 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()],)],)],);}
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装git工具

下载安装地址&#xff1a; Git - Downloading Package (git-scm.com) 命令安装&#xff1a;创建文件夹下载路径 启动powershell 输入命令&#xff1a;winget install --id Git.Git -e --source winget 等待下载安装

查询子节点 postgresql

数据库为postgresql WITH RECURSIVE cte AS (SELECTn. ID,n. com_name,n."parentId" AS pidFROMcompany AS nWHEREn. ID = 2UNION ALLSELECTr. ID,r. com_name,cte. ID AS pidFROMcteJOIN company AS r ON r.

Linux命令之nc命令

一、命令简介 nc是netcat的简写&#xff0c;是一个功能强大的网络工具&#xff0c;有着网络界的瑞士军刀美誉。nc命令在linux系统中实际命令是ncat&#xff0c;nc是软连接到ncat。nc命令的主要作用如下&#xff1a; 实现任意TCP/UDP端口的侦听&#xff0c;nc可以作为server以T…

electron打包exe桌面项目打开控制台

阿丹&#xff1a; 之前一直在写web项目&#xff0c;按F12开发控制台很方便但是。现在项目涉及到了桌面的应用这就需要在打包的过程中进行书写配置文件main中添加指令来在app加载完成后打开控制台&#xff0c;这样方便我们寻找报错。 打开方式1 因为使用的工具是electron所以找…

华为云书库《Spring Boot2系列实战教程》电子书

华为开发者大会PaaS生态电子书推荐&#xff0c;助你成为了不起的开发者&#xff01; 处理Spring Boot 常见企业级需求&#xff0c;《Spring Boot2系列实战教程》来了&#xff01; 点击下方进入华为云官网 https://auth.huaweicloud.com/authui/login.html?localezh-cn&…

win11预览版更新,并尝试使用Copilot

文章目录 win11预览版更新&#xff0c;并使用Copilot先说结果所需内容具体操作更新操作系统版本更新Edge安装ViVeTool v0.3.3 测试Copilot问题唯一优点 总结 win11预览版更新&#xff0c;并使用Copilot 先说结果 体验一言难尽&#xff0c;就相当于是一个快捷聊天提问窗口。 自…

Spring Boot 中的监控及使用

Spring Boot 中的监控及使用 Spring Boot 是一个非常流行的 Java 应用程序开发框架&#xff0c;它提供了一种快速构建应用程序的方法。除此之外&#xff0c;Spring Boot 还提供了一系列的监控功能&#xff0c;方便开发人员对应用程序进行监控和管理。本文将讨论 Spring Boot 中…

Java数组的定义与使用

文章目录 数组的基本概念Java数组的语法数组的使用JVM的内存分布基本类型变量与引用类型变量的区别数组深浅拷贝 数组的基本概念 数组&#xff1a;可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。比如现实中的车库&#xff1a; 数组中存放的元素其类型相同数组…

算数运算符

运算符介绍&#xff1a;运算符是一种特殊的符号&#xff0c;用以表示数据的运算、赋值和比较等。 算术运算符赋值运算符关系运算符逻辑运算符位运算符三元运算符 算术运算符 算术运算符是对数值类型的变量进行运算的。 % 取模&#xff0c;取余 在 % 的本质&#xff0c;a % b…

[桌面运维] 显示器 色准,色域,色深,分辨率,带宽,刷新率的基本概念,图像呈现的基本原理

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

暑假第五天打卡

Java //1、练习题&#xff1a;判断如下代码是否编译通过&#xff0c;如果能&#xff0c;结果是多少&#xff1f; short s1 120; short s2 8; short s3 s1 s2; //编译不通过&#xff0c;因为s1s2自动提示为int类型 //3、练习题&#xff1a;判断如下代码是否编译通过&am…

OpenCV使用`clone()`函数来进行深度拷贝,拷贝后的`image_clone`修改不会影响原始图像`image`

这是完整的代码: #include <opencv2/opencv.hpp>int main() {// 创建一个白色的图像cv::Mat image(500, 500, CV_8UC3, cv