保存数据到本地磁盘是应用程序常用功能之一,比如保存用户登录信息、用户配置信息等。而保存这些信息通常使用 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
支持的数据类型有 int
、double
、bool
、string
、stringList
。
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
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的其他操作可以自行百度
数据库操作
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()
],
)
],
)
],
);
}
}