1. 前言
Android 和 iOS 中都会有 SQLite,那么 Flutter 有没有呢?答案是肯定有的。Flutter 中的 SQLite 数据库是同时支持 Android 和 iOS 的,它的名字叫 sqflite ,支持事务和批量操作,支持插入/查询/更新/删除操作等,是轻量级的关系型数据库。
下面先简单实现一个登录界面,进行简单的数据操作:
//用无状态控件显示
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
//主题色
theme: ThemeData(
//设置为蓝色
primarySwatch: Colors.red),
//这是一个Widget对象,用来定义当前应用打开的时候,所显示的界面
home: DataBaseWidget(),
);
}
}
//主框架
class DataBaseWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _DataBaseState();
}
}
class _DataBaseState extends State<DataBaseWidget> {
@override
Widget build(BuildContext context) {
return new Scaffold(
//appBar
appBar: AppBar(
title: Text("Sqlite简单操作"),
//标题居中
centerTitle: true,
),
body: new ListView(
children: <Widget>[
//用户输入用户信息widget
Padding(
padding: const EdgeInsets.only(left: 16, right: 16),
child: InputMessageWidget(),
),
//数据库表的一些基本操作,增,删,改,查
Padding(
padding: const EdgeInsets.all(16),
child: SqliteHandleWidget(),
),
],
),
);
}
}
用户输入信息的 Widget 组件:
//用户名和密码
class InputMessageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
//这个是为了用户输入结束后,让密码输入框获取到焦点
FocusNode secondTextFieldNode = FocusNode();
return Column(
children: <Widget>[
TextField(
//文字内容改变触发
onChanged: (user) {
//获取用户名
username = user;
},
//输入法装饰器
decoration: InputDecoration(
//标签
labelText: '名字',
//hint 提示用户输入什么
hintText: '请输入英文或者数字'),
//最大为一行
maxLines: 1,
//文字提交触发
onSubmitted: (result) {
FocusScope.of(context).reparentIfNeeded(secondTextFieldNode);
},
),
TextField(
onChanged: (pwd) {
//获取用户密码
password = pwd;
},
//是否隐藏输入 false 表示不隐藏,true表示隐藏
obscureText: true,
maxLines: 1,
decoration: InputDecoration(
labelText: '密码',
hintText: '请输入密码',
),
//键盘输入类型
keyboardType: TextInputType.text,
onSubmitted: (data) {},
),
],
);
}
}
对数据库表操作的按钮布局如下:
//数据库组件操作
class SqliteHandleWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _SqliteHandleWidgetState();
}
}
class _SqliteHandleWidgetState extends State<SqliteHandleWidget> {
//数据库名称
String myDataBase = "usermessage.db";
//数据库路径
String myDataBasePath = "";
//数据库中的表 简单一点,就创建三个字段,分别是主键,用户名,密码
String sql_createUserTable = "CREATE TABLE user("
"id INTEGER PRIMARY KEY,"
"username TEXT,"
"password TEXT)";
//查找数据库表的数目
String sql_queryCount = 'SELECT COUNT(*) FROM user';
//具体查找数据库表的所有信息
String sql_queryMessage = 'SELECT * FROM user';
//这是从数据库表返回数据
var _data;
@override
Widget build(BuildContext context) {
return Column(
//交叉轴设置中间
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: 40.0,
child: RaisedButton(
textColor: Colors.black,
child: Text("创建数据库表"),
onPressed: null,
),
),
Row(
//主轴方向中心对齐
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new RaisedButton(
textColor: Colors.black,
child: new Text('增'),
onPressed: null),
new RaisedButton(
textColor: Colors.black,
child: new Text('删'),
onPressed: null),
new RaisedButton(
textColor: Colors.black,
child: new Text('改'),
onPressed: null),
],
),
Row(
//主轴方向中心对齐
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new RaisedButton(
textColor: Colors.black,
child: new Text('查条数'),
onPressed: null),
new RaisedButton(
textColor: Colors.black,
child: new Text('查信息'),
onPressed: null),
],
),
Padding(
padding: const EdgeInsets.all(16.0),
child: new Text('具体结果是:$_data'),
),
],
);
}
}
在上面_SqliteHandleWidgetState
赋值数据库名字为usermessage.db
,创建数据库表user
语句很简单,就三个字段,分别是主键,用户名,用户密码,界面如下:
2. 创建数据库和数据表
首先在 pubspec.xml
文件添加依赖:可以到 Dart 包管理网站去查找 sqlite 依赖最新版本。
sqflite: ^1.1.0
并在文件引入:
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
注意:对于数据库的操作都是耗时操作,都要通过异步来处理。
//创建数据库
Future<String> createDataBase(String db_name) async {
//在文档目录建立
var document = await getApplicationDocumentsDirectory();
//获取路径 join是path包下的方法,就是将两者路径连接起来
String path = join(document.path, db_name);
//逻辑是如果数据库存在就把它删除然后创建
var _directory = new Directory(dirname(path));
bool exists = await _directory.exists();
if (exists) {
//必存在 这里是为了每次创建数据库表先表删除则删除数据库表
await deleteDatabase(path);
} else {
try {
//不存在则创建目录 如果[recursive]为false,则只有路径中的最后一个目录是
//创建。如果[recursive]为真,则所有不存在的路径
//被创建。如果目录已经存在,则不执行任何操作。
await new Directory(dirname(path)).create(recursive: true);
} catch (e) {
print(e);
}
}
return path;
}
//创建数据库表方法
cratedb_table() async {
//得到数据库的路径
myDataBasePath = await createDataBase(myDataBase);
//打开数据库
Database my_db = await openDatabase(myDataBasePath);
//创建数据库表
await my_db.execute(sql_createUserTable);
//关闭数据库
await my_db.close();
setState(() {
_data = "创建usermessage.db成功,创建user表成功~";
});
}
给按钮添加点击方法:
child: RaisedButton(
textColor: Colors.black,
child: Text("创建数据库表"),
onPressed: cratedb_table,
),
运行,安装完apk
,用Device File Exploder
来看看内部存储文件:
下面点击创建数据库,后synchronize
来刷新一下:
发现在 app_flutter
下多了usermessage.db
文件,确实数据库创建成功了,那继续下面的操作。
3. 增加数据
下面实现增加数据,可以用rawInsert
或者db.insert
方式对数据库表数据进行增加(插入),实际上都是通过insert into
方式来插入数据表,下面就用rawInsert
方式来增加一条数据:
//增加方法
addData() async {
//首先打开数据库
Database my_db = await openDatabase(myDataBasePath);
//插入数据
String add_sql = "INSERT INTO user(username,password) VALUES('$username','$password')";
await my_db.transaction((tran) async{
await tran.rawInsert(add_sql);
});
//关闭数据库
await my_db.close();
setState(() {
_data = "增加一条数据成功,名字是:$username,密码是:$password";
});
}
4. 查询具体数据
为了配合增加数据,把查询数据库表的功能实现:
//查询具体数值
queryDetail() async{
//打开数据库
Database my_db = await openDatabase(myDataBasePath);
//将数据放到集合里面显示
List<Map> dataList = await my_db.rawQuery(sql_queryMessage);
await my_db.close();
setState(() {
_data = "具体数据详情如下:$dataList";
});
}
查询数据表很简单,实际上只用rawQuery这个方法,把增加和查询方法绑定到按钮点击上:
new RaisedButton(
textColor: Colors.black, child: new Text('改'), onPressed: null),
....
new RaisedButton(
textColor: Colors.black,
child: new Text('查信息'),
onPressed: queryDetail),
验证结果,流程是:
- 先输入用户名和密码
- 点击增加
- 点击查信息
运行结果如下:
5. 删除数据
下面实现删除数据:
//删除一条数据
delete() async {
Database my_db = await openDatabase(myDataBasePath);
//根据id来删除 也可以根据其他信息来删除 例如名字
String delete_ssql = "DELETE FROM user WHERE id = ?";
//返回所更改的数目
int delete_count = await my_db.rawDelete(delete_ssql,['1']);
//关闭数据库
await my_db.close();
//状态更新
setState(() {
if(delete_count == 1){
_data = "删除成功~";
} else {
_data = "删除失败,请看错误日志~";
}
});
}
6. 修改数据
修改数据我相信在平时开发中是用的最频繁的操作了,直接上实现例子:
//修改数据方法
update() async{
//数据库
Database my_db = await openDatabase(myDataBasePath);
String update_sql = "UPDATE user SET username = ? WHERE id = ?";
await my_db.rawUpdate(update_sql,['paul','1']);
await my_db.close();
setState(() {
_data = "数据修改成功,请查阅~";
});
}
上面用了rawUpdate
对数据库表进行内容数据更新,也可以用db.update
来更新,自己可以根据需求变更去修改固定字段或者整条数据。上面我是根据 id 这个条件来修改一条数据,将 id 为 1 的数据的名字改为paul
。
7. 查询条数
//查询有几条
query_num() async{
//数据库
Database my_db = await openDatabase(myDataBasePath);
//用sqflite包的方法firstInValue
int data_count = Sqflite.firstIntValue(await my_db.rawQuery(sql_queryCount));
await my_db.close();
setState(() {
_data = "数据条数:$data_count";
});
}