假设一个列表被赋值给一个SQLite数据库的查询,如何保证这个列表不为空?扑
Assume a list is being assigned the query of a SQLite database, how to ensure that the list is not null? Flutter
我正在使用 sqflite 包制作一个带有 SQLite 数据库的 Flutter 应用程序。我有一个带有必要方法的数据库助手 class。在其中一个页面中,我想将数据显示为卡片列表。我还将图像存储到数据库中,因此在同一页面中我必须将图像转换回文件。在那个名为 DataPage 的页面的 class 中,我创建了一个名为 query 的方法,它调用数据库的查询方法并将该值分配给一个名为 listLokasi 的列表。我还制作了一个名为 convert 的方法,它调用 List.generate,其中一个参数是 listLokasi.length。同时,我将这 2 个方法放在 _DataPageState 的构造函数中,因为 DataPage 是一个有状态的小部件。问题是当我 运行 应用程序显示一个错误时显示 NoSuchMethodError,因为我试图在 null 上调用 length,这意味着 listLokasi 为 null。所以我将断言放在查询方法中,在查询方法之后的构造函数中,以及在转换方法中。结果是查询方法中的断言没有触发,而构造函数中的断言立即触发。我检查了我的数据库助手 class 并检查了我的代码,但我找不到我的代码中的缺陷。对此问题的任何帮助将不胜感激。我将在下面显示代码。
这是数据库助手 class。
class DatabaseHelper {
static final _instance = DatabaseHelper._internal();
DatabaseHelper._internal();
factory DatabaseHelper() {
return _instance;
}
Database db;
Future initDatabase() async {
var databasePath = await getDatabasesPath();
var path = join(databasePath, 'table.db');
db = await openDatabase(path, version: 1, onCreate: onCreate);
}
onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE lokasi
(id INTEGER PRIMARY KEY,
name TEXT,
description TEXT,
category TEXT,
latitude REAL,
longitude REAL,
image BLOB)
''');
}
Future<Lokasi> insert(Lokasi lokasi) async {
await db.insert('lokasi', lokasi.toJson());
return lokasi;
}
Future<List<Lokasi>> query() async {
var list = await db.query('lokasi');
return List.generate(list.length, (i) => Lokasi.fromJson(list[i]));
}
}
这是数据页class。
class DataPage extends StatefulWidget {
final savedUsername;
const DataPage({this.savedUsername = 'User'});
@override
_DataPageState createState() => _DataPageState();
}
class _DataPageState extends State<DataPage> {
DatabaseHelper db = DatabaseHelper();
List<Lokasi> listLokasi;
List<LokasiConvert> listLokasiConvert;
_DataPageState() {
query();
assert(listLokasi != null);
convert();
}
convert() {
assert(listLokasi != null);
listLokasiConvert = List.generate(
listLokasi.length,
(i) => LokasiConvert(
name: listLokasi[i].name,
description: listLokasi[i].category,
category: listLokasi[i].category,
latitude: listLokasi[i].latitude,
longitude: listLokasi[i].longitude,
image: File.fromRawPath(listLokasi[i].image),
),
);
}
Future<List<Lokasi>> query() async {
listLokasi = await db.query();
assert(listLokasi != null);
return listLokasi;
}
void sendUsername(BuildContext context) {
String username = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MainPage(username: username),
),
);
}
void sendUsernameToChart(BuildContext context) {
String chartUsername = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChartPage(savedUsername: chartUsername),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('Data'),
actions: [
RaisedButton(
child: Text('Logout'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
RaisedButton(
child: Text('Main'),
onPressed: () {
sendUsername(context);
},
),
RaisedButton(
child: Text('Charts'),
onPressed: () {
sendUsernameToChart(context);
},
),
],
),
body: ListView.builder(
itemBuilder: (context, i) {
return Card(
child: Row(
children: [
Image.file(
listLokasiConvert[i].image,
width: 100,
height: 100,
),
Column(
children: [
Text(listLokasiConvert[i].name),
Text(listLokasiConvert[i].category),
Text(listLokasiConvert[i].description),
Text('Coordinates: ' +
listLokasiConvert[i].latitude.toString() +
', ' +
listLokasiConvert[i].longitude.toString()),
],
)
],
));
},
itemCount: listLokasiConvert.length,
),
);
}
}
再次感谢您的帮助。
也许你可以试试这个。希望对你有帮助。
db.query().then((value) {
setState(() {
listLokasi = value
});
});
正如我在过程中发现的那样,解决方案实际上很简单。该列表是未来的,所以我应该使用未来的构建器,然后用未来的构建器包装列表视图构建器。让我展示一下我完成的那个特定页面的代码。
class DataPage extends StatefulWidget {
final savedUsername;
const DataPage({this.savedUsername = 'User'});
@override
_DataPageState createState() => _DataPageState();
}
class _DataPageState extends State<DataPage> {
DatabaseHelper db = DatabaseHelper();
List<Lokasi> listLokasi;
delete(value) async {
await db.delete(value);
}
Future<List<Lokasi>> query() async {
listLokasi = await db.query();
return listLokasi;
}
void sendUsername(BuildContext context) {
String username = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MainPage(username: username),
),
);
}
void sendUsernameToChart(BuildContext context) {
String chartUsername = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChartPage(savedUsername: chartUsername),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('Data'),
actions: [
RaisedButton(
child: Text('Logout'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
RaisedButton(
child: Text('Main'),
onPressed: () {
sendUsername(context);
},
),
RaisedButton(
child: Text('Charts'),
onPressed: () {
sendUsernameToChart(context);
},
),
],
),
body: FutureBuilder(
future: query(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (context, i) {
return Card(
child: Row(
children: [
Column(
children: [
Text(snapshot.data[i].name),
Text(snapshot.data[i].category),
Text(snapshot.data[i].description),
Text('Coordinates: ' +
snapshot.data[i].latitude.toString() +
', ' +
snapshot.data[i].longitude.toString()),
],
),
Container(
width: 100,
height: 100,
child: Image.memory(snapshot.data[i].image),
),
Container(
width: 30,
height: 30,
child: IconButton(
onPressed: () {
db.delete(snapshot.data[i].name);
setState(() {});
},
icon: Icon(Icons.delete, size: 30),
iconSize: 30,
),
)
],
),
);
},
itemCount: snapshot.data.length,
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
我正在使用 sqflite 包制作一个带有 SQLite 数据库的 Flutter 应用程序。我有一个带有必要方法的数据库助手 class。在其中一个页面中,我想将数据显示为卡片列表。我还将图像存储到数据库中,因此在同一页面中我必须将图像转换回文件。在那个名为 DataPage 的页面的 class 中,我创建了一个名为 query 的方法,它调用数据库的查询方法并将该值分配给一个名为 listLokasi 的列表。我还制作了一个名为 convert 的方法,它调用 List.generate,其中一个参数是 listLokasi.length。同时,我将这 2 个方法放在 _DataPageState 的构造函数中,因为 DataPage 是一个有状态的小部件。问题是当我 运行 应用程序显示一个错误时显示 NoSuchMethodError,因为我试图在 null 上调用 length,这意味着 listLokasi 为 null。所以我将断言放在查询方法中,在查询方法之后的构造函数中,以及在转换方法中。结果是查询方法中的断言没有触发,而构造函数中的断言立即触发。我检查了我的数据库助手 class 并检查了我的代码,但我找不到我的代码中的缺陷。对此问题的任何帮助将不胜感激。我将在下面显示代码。
这是数据库助手 class。
class DatabaseHelper {
static final _instance = DatabaseHelper._internal();
DatabaseHelper._internal();
factory DatabaseHelper() {
return _instance;
}
Database db;
Future initDatabase() async {
var databasePath = await getDatabasesPath();
var path = join(databasePath, 'table.db');
db = await openDatabase(path, version: 1, onCreate: onCreate);
}
onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE lokasi
(id INTEGER PRIMARY KEY,
name TEXT,
description TEXT,
category TEXT,
latitude REAL,
longitude REAL,
image BLOB)
''');
}
Future<Lokasi> insert(Lokasi lokasi) async {
await db.insert('lokasi', lokasi.toJson());
return lokasi;
}
Future<List<Lokasi>> query() async {
var list = await db.query('lokasi');
return List.generate(list.length, (i) => Lokasi.fromJson(list[i]));
}
}
这是数据页class。
class DataPage extends StatefulWidget {
final savedUsername;
const DataPage({this.savedUsername = 'User'});
@override
_DataPageState createState() => _DataPageState();
}
class _DataPageState extends State<DataPage> {
DatabaseHelper db = DatabaseHelper();
List<Lokasi> listLokasi;
List<LokasiConvert> listLokasiConvert;
_DataPageState() {
query();
assert(listLokasi != null);
convert();
}
convert() {
assert(listLokasi != null);
listLokasiConvert = List.generate(
listLokasi.length,
(i) => LokasiConvert(
name: listLokasi[i].name,
description: listLokasi[i].category,
category: listLokasi[i].category,
latitude: listLokasi[i].latitude,
longitude: listLokasi[i].longitude,
image: File.fromRawPath(listLokasi[i].image),
),
);
}
Future<List<Lokasi>> query() async {
listLokasi = await db.query();
assert(listLokasi != null);
return listLokasi;
}
void sendUsername(BuildContext context) {
String username = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MainPage(username: username),
),
);
}
void sendUsernameToChart(BuildContext context) {
String chartUsername = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChartPage(savedUsername: chartUsername),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('Data'),
actions: [
RaisedButton(
child: Text('Logout'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
RaisedButton(
child: Text('Main'),
onPressed: () {
sendUsername(context);
},
),
RaisedButton(
child: Text('Charts'),
onPressed: () {
sendUsernameToChart(context);
},
),
],
),
body: ListView.builder(
itemBuilder: (context, i) {
return Card(
child: Row(
children: [
Image.file(
listLokasiConvert[i].image,
width: 100,
height: 100,
),
Column(
children: [
Text(listLokasiConvert[i].name),
Text(listLokasiConvert[i].category),
Text(listLokasiConvert[i].description),
Text('Coordinates: ' +
listLokasiConvert[i].latitude.toString() +
', ' +
listLokasiConvert[i].longitude.toString()),
],
)
],
));
},
itemCount: listLokasiConvert.length,
),
);
}
}
再次感谢您的帮助。
也许你可以试试这个。希望对你有帮助。
db.query().then((value) {
setState(() {
listLokasi = value
});
});
正如我在过程中发现的那样,解决方案实际上很简单。该列表是未来的,所以我应该使用未来的构建器,然后用未来的构建器包装列表视图构建器。让我展示一下我完成的那个特定页面的代码。
class DataPage extends StatefulWidget {
final savedUsername;
const DataPage({this.savedUsername = 'User'});
@override
_DataPageState createState() => _DataPageState();
}
class _DataPageState extends State<DataPage> {
DatabaseHelper db = DatabaseHelper();
List<Lokasi> listLokasi;
delete(value) async {
await db.delete(value);
}
Future<List<Lokasi>> query() async {
listLokasi = await db.query();
return listLokasi;
}
void sendUsername(BuildContext context) {
String username = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MainPage(username: username),
),
);
}
void sendUsernameToChart(BuildContext context) {
String chartUsername = widget.savedUsername;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChartPage(savedUsername: chartUsername),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('Data'),
actions: [
RaisedButton(
child: Text('Logout'),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName('/'));
},
),
RaisedButton(
child: Text('Main'),
onPressed: () {
sendUsername(context);
},
),
RaisedButton(
child: Text('Charts'),
onPressed: () {
sendUsernameToChart(context);
},
),
],
),
body: FutureBuilder(
future: query(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (context, i) {
return Card(
child: Row(
children: [
Column(
children: [
Text(snapshot.data[i].name),
Text(snapshot.data[i].category),
Text(snapshot.data[i].description),
Text('Coordinates: ' +
snapshot.data[i].latitude.toString() +
', ' +
snapshot.data[i].longitude.toString()),
],
),
Container(
width: 100,
height: 100,
child: Image.memory(snapshot.data[i].image),
),
Container(
width: 30,
height: 30,
child: IconButton(
onPressed: () {
db.delete(snapshot.data[i].name);
setState(() {});
},
icon: Icon(Icons.delete, size: 30),
iconSize: 30,
),
)
],
),
);
},
itemCount: snapshot.data.length,
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}