在本教程中,我们将介绍如何在flutter中使用sqlite。 SQLite是用于移动设备和某些计算机的SQL引擎。 我们可以使用它来保存应用程序的数据。 持久性存储对于在加载新数据时缓存网络呼叫和脱机应用程序很有用。
Flutter中的SQLite可用于在Android和iOS应用中持久存储数据。 在本教程中,我们将构建一个简单的应用程序以将数据记录在诸如杂货店列表之类的列表中。 这是该应用程序的屏幕截图。
注意:如果您了解抖动的一些基本知识,它将很有用。 这篇文章将是一个很好的起点。
继续创建一个新项目。 我将其命名为flutter_sqlite ,您可以随意命名。
➜ ~ flutter create flutter_sqflite
我们将删除默认代码和注释,现在仅放入容器中。 在运行该应用程序时,您将看到一个空白屏幕。
import 'package:flutter/material.dart' ; void main() {
runApp(MyApp()); } MyApp class extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo' ,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Listify' ),
);
} } class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this .title}) : super (key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(),
);
} }
接下来,将以下依赖项添加到pubspec.yaml文件中:
name: flutter_sqflite description: A new Flutter project. publish_to: 'none' version: 1.0 . 0 + 1 environment:
sdk: ">=2.7.0 <3.0.0" dependencies:
flutter:
sdk: flutter
sqflite:
cupertino_icons: ^ 0.1 . 3 dev_dependencies:
flutter_test:
sdk: flutter flutter:
uses-material-design: true
我们将创建一个基本的文本字段,一个要保存的按钮以及一个显示待办事项的列表。 首先,让我们继续创建输入字段。 这将在脚手架体内:
import 'package:flutter/material.dart' ; void main() {
runApp(MyApp()); } MyApp class extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo' ,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Listify' ),
);
} } class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this .title}) : super (key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all( 16 ),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextFormField(
decoration: InputDecoration(hintText: "Enter a task" ),
controller: textController,
),
)
],
)
],
),
),
);
} }
添加TextEditingController作为此类的属性,这将帮助我们从此字段中检索数据。
class _MyHomePageState extends State<MyHomePage> {
TextEditingController textController = new TextEditingController(); ...
接下来,创建一个按钮来保存待办事项:
import 'package:flutter/material.dart' ; void main() {
runApp(MyApp()); } MyApp class extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo' ,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Listify' ),
);
} } class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this .title}) : super (key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {
TextEditingController textController = new TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all( 16 ),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextFormField(
decoration: InputDecoration(hintText: "Enter a task" ),
controller: textController,
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: null ,
),
],
)
],
),
),
);
} }
为了简单起见,我们不会添加验证,您可以在您的应用程序中进行验证。 我们将继续把重点放在在flutter中使用sqlite。
创建输入字段和按钮后,让我们添加一个列表以显示项目。 但是为此,我们需要创建项目模型。 创建一个名为todo.dart的文件并添加以下类:
class Todo {
int id;
String title;
Todo({ this .id, this .title});
Map<String, dynamic> toMap() {
return { 'id' : id, 'title' : title};
} }
现在,让我们继续创建列表。 如果您想知道如何在Flutter中创建ListView,可以查看这篇文章 。 我们将列表添加到Scaffold的主体中。
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this .title}) : super (key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {
TextEditingController textController = new TextEditingController();
List<Todo> taskList = new List();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all( 16 ),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextFormField(
decoration: InputDecoration(hintText: "Enter a task" ),
controller: textController,
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: null ,
)
],
),
SizedBox(height: 20 ),
Expanded(
child: Container(
child: taskList.isEmpty
? Container()
: ListView.builder(itemBuilder: (ctx, index) {
if (index == taskList.length) return null ;
return ListTile(
title: Text(taskList[index].title),
leading: Text(taskList[index].id.toString()),
);
}),
),
)
],
),
),
);
} }
我们正在使用ListTile,它是一个出色的小部件,为我们提供了列表行的基本布局。
完成此操作后,现在该进行下一步了,建立起混乱的sqlite。
创建一个名为DatabaseHelper.dart的文件,我们将使用工厂构造函数将DatabaseHelper创建为单例。 将以下代码添加到DatabaseHelper.dart
import 'package:path/path.dart' ; import 'package:sqflite/sqflite.dart' ; import 'todo.dart' ; class DatabaseHelper {
static final _databaseName = "todo.db" ;
static final _databaseVersion = 1 ;
static final table = 'todo' ;
static final columnId = 'id' ;
static final columnTitle = 'title' ;
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database _database;
Future<Database> get database async {
if (_database != null ) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
String path = join(await getDatabasesPath(), _databaseName);
return await openDatabase(path,
version: _databaseVersion, onCreate: _onCreate);
}
// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute( '' '
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY AUTOINCREMENT,
$columnTitle FLOAT NOT NULL
)
'' ');
} }
静态字段是有关我们数据库的信息,例如版本,表名,数据库名和列名。 DatabaseHelper._privateConstructor()是我们在Dart中使用工厂构造函数的方式。
接下来,让我们添加一些方法来插入,删除表,读取所有数据并清除表中的所有数据。
Future< int > insert(Todo todo) async {
Database db = await instance.database;
var res = await db.insert(table, todo.toMap());
return res; } Future<List<Map<String, dynamic>>> queryAllRows() async {
Database db = await instance.database;
var res = await db.query(table, orderBy: "$columnId DESC" );
return res; } Future< int > delete( int id) async {
Database db = await instance.database;
return await db.delete(table, where: '$columnId = ?' , whereArgs: [id]); } Future< void > clearTable() async {
Database db = await instance.database;
return await db.rawQuery( "DELETE FROM $table" ); }
注意:对于queryAllRows,我们使用orderBy:“ $ columnId DESC”,它将按id的降序对行进行排序。 默认情况下,它是递增的。
这是在flutter中设置SQLite的基础。 现在,我们将看到如何使用此帮助器类添加和删除数据。 这篇文章引用了一些帮助类的代码。 最终的帮助器类如下所示:
import 'package:path/path.dart' ; import 'package:sqflite/sqflite.dart' ; import 'todo.dart' ; class DatabaseHelper {
static final _databaseName = "todo.db" ;
static final _databaseVersion = 1 ;
static final table = 'todo' ;
static final columnId = 'id' ;
static final columnTitle = 'title' ;
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database _database;
Future<Database> get database async {
if (_database != null ) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
String path = join(await getDatabasesPath(), _databaseName);
return await openDatabase(path,
version: _databaseVersion, onCreate: _onCreate);
}
// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute( '' '
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY AUTOINCREMENT,
$columnTitle FLOAT NOT NULL
)
'' ');
}
Future< int > insert(Todo todo) async {
Database db = await instance.database;
var res = await db.insert(table, todo.toMap());
return res;
}
Future<List<Map<String, dynamic>>> queryAllRows() async {
Database db = await instance.database;
var res = await db.query(table, orderBy: "$columnId DESC" );
return res;
}
Future< int > delete( int id) async {
Database db = await instance.database;
return await db.delete(table, where: '$columnId = ?' , whereArgs: [id]);
}
Future< void > clearTable() async {
Database db = await instance.database;
return await db.rawQuery( "DELETE FROM $table" );
} }
如果您想尝试清除表,我还添加了clearTable方法。
每当应用重启时,我们都想用数据初始化列表。 为此,我们将在initState()生命周期回调中使用queryAllRows方法。
覆盖_MyHomePageState类中的initState()方法,并添加以下代码。
@override void initState() {
super .initState();
DatabaseHelper.instance.queryAllRows().then((value) {
setState(() {
value.forEach((element) {
taskList.add(Todo(id: element[ 'id' ], title: element[ "title" ]));
});
});
}).catchError((error) {
print(error);
}); }
应用启动时,将调用initState,我们将从数据库中读取数据。 当数据可用时, SetState将更新UI,我们的ListView将负责其余的工作。
要将输入的任务添加到我们的数据库中,我们将在main.dart文件中创建一个_addToDb方法。 这将在单击“ +”按钮时调用:
void _addToDb() async {
String task = textController.text;
var id = await DatabaseHelper.instance.insert(Todo(title: task));
setState(() {
taskList.insert( 0 , Todo(id: id, title: task));
}); }
首先,我们将从字段中获取文本,然后将其添加到db中,最后更新我们的视图。
注意:由于我们在数据库中将id标记为AUTO INCREMENT,因此在插入时无需设置Todo对象的id。 Insert方法将为我们提供插入对象的ID。 我们可以使用它来更新UI。
删除行
现在,剩下要做的就是能够删除数据库中的记录。 使用尾随参数将图标添加到我们的ListTile行:
return ListTile(
title: Text(taskList[index].title),
leading: Text(taskList[index].id.toString()),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _deleteTask(taskList[index].id),
), );
对于onPressed,我们将创建一个_deleteTask方法,该方法将使用ID删除待办事项。 最后,我们将像以前一样更新UI:
void _deleteTask( int id) async {
await DatabaseHelper.instance.delete(id);
setState(() {
taskList.removeWhere((element) => element.id == id);
}); }
至此,我们完成了。 最终的main.dart文件如下所示:
import 'package:flutter/material.dart' ; import 'package:flutter_sqflite/database_helper.dart' ; import 'package:flutter_sqflite/todo.dart' ; void main() {
runApp(MyApp()); } MyApp class extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo' ,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Listify' ),
);
} } class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this .title}) : super (key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> {
TextEditingController textController = new TextEditingController();
List<Todo> taskList = new List();
@override
void initState() {
super .initState();
DatabaseHelper.instance.queryAllRows().then((value) {
setState(() {
value.forEach((element) {
taskList.add(Todo(id: element[ 'id' ], title: element[ "title" ]));
});
});
}).catchError((error) {
print(error);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all( 16 ),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: TextFormField(
decoration: InputDecoration(hintText: "Enter a task" ),
controller: textController,
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: _addToDb,
)
],
),
SizedBox(height: 20 ),
Expanded(
child: Container(
child: taskList.isEmpty
? Container()
: ListView.builder(itemBuilder: (ctx, index) {
if (index == taskList.length) return null ;
return ListTile(
title: Text(taskList[index].title),
leading: Text(taskList[index].id.toString()),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _deleteTask(taskList[index].id),
),
);
}),
),
)
],
),
),
);
}
void _deleteTask( int id) async {
await DatabaseHelper.instance.delete(id);
setState(() {
taskList.removeWhere((element) => element.id == id);
});
}
void _addToDb() async {
String task = textController.text;
var id = await DatabaseHelper.instance.insert(Todo(title: task));
setState(() {
taskList.insert( 0 , Todo(id: id, title: task));
});
} }
这里要注意的一件事是,当我们添加/删除项目时,UI会完全重建。 可以通过在flutter中使用Provider模式来进一步优化,我之前已经讨论过。 一定要检查一下。
结论
在本教程中,我们了解了SQLite如何在Flutter中工作。 我们增加了添加,从列表中删除任务以及同时更新列表的功能。
翻译自: https://www.javacodegeeks.com/2020/06/using-sqlite-in-flutter-tutorial.html