我正在创建一个flutter应用程序,并创建了一个页面,该页面从sqlite数据库中提取数据并动态加载窗口小部件,该页面加载时将显示来自sqlite db的数据。由于某些原因,窗口小部件未加载。当我热重新加载应用程序时,它仅以调试模式加载动态窗口小部件。
这是我的代码:
Users userList = new Users();
List details = new List<Widget>();
var db = new DB_Helper();
_addToUserList(Map<dynamic, dynamic> json)
{
userList.membersList.add(json);
return userList.membersList;
}
List<Widget> getTeamMembers()
{
// Get data from db
db.getMembers().then((data) {
// clear list to prevent repeating if page refreshes
userList.membersList.clear();
details.clear();
for (Members m in data)
{
Map<String, dynamic> json;
json =
{
"member_id": m.memberId,
"member_name": m.memberName,
"member_email": m.memberEmail
};
_addToUserList(json);
}
for (Map<dynamic, dynamic> u in userList.membersList) {
Map<String, dynamic> js = u;
var emailCtrl = new TextEditingController();
var name = js["member_name"];
emailCtrl.text = js["member_email"];
details.add(
new Card(
color: Colors.blue,
margin: EdgeInsets.all(2),
child: ExpansionTile(
title: Text(name),
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
width: 280,
padding: EdgeInsets.all(0),
margin: EdgeInsets.all(0),
child: TextField(
enabled: false,
controller: emailCtrl,
style: TextStyle(color: Colors.purple),
decoration: InputDecoration(
labelText: "EMAIL:",
labelStyle: new TextStyle(color: Colors.black),
border: InputBorder.none,
),
),
),
],
),
),
],
),
],
),
),
);
}
});
return details;
}
我尝试获取数据并将其存储在initState()中的列表中,但是该页面仍然空白。
我在查询sqlite时曾尝试使用await,但是它在我称为小部件的支架主体属性内引发了错误。
唯一正确加载的时间是,当我删除查询数据库的代码并用值对userList进行硬编码时,而不是从sqlite中将其拔出。查询sqlite db似乎阻止了小部件的显示。如何从sqlite中提取数据并将其添加到动态小部件中以在页面加载时显示?
答案 0 :(得分:0)
您的代码肯定是一团糟。
您应该改用ListView.builder
。您不应将任何Dart for循环用于构建窗口小部件。只需正确设置数据数组并使用ListView.builder来构建Card和其他Widget。这是使用ListView.builder
的示例:
ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int i) {
return Dismissible(
key: ObjectKey(list[i]),
background: Container(
alignment: AlignmentDirectional.centerEnd,
color: Colors.red,
child: Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
child: Icon(
Icons.delete,
color: Colors.white,
),
),
),
confirmDismiss: (direction) async {
if (direction == DismissDirection.startToEnd) {
/// edit item
return false;
} else if (direction == DismissDirection.endToStart) {
/// delete
return true;
}
},
onDismissed: (direction) {
setState(() {
var paymentMethod = list[i];
list.removeAt(i);
_showDeletePaymentDialog(paymentMethod);
});
},
child: Card(
color: BmsColors.primaryBackgroundColor,
elevation: 2.0,
child: ListTile(
title: Text(
'xxxx-${list[i].last4}',
style: UIUtil.getTxtStyleCaption(),
),
subtitle: Text(
list[i].brandDisplay,
style: UIUtil.getTxtStyleCaption(),
),
leading: CardUtils.getCardIcon(list[i].brand),
trailing: (list[i].isDefault)
? Icon(
Icons.check_circle,
size: 32,
color: BmsColors.primaryForegroundColor,
)
: Container(
width: 32,
),
onTap: () {
debugPrint('Tapped on ');
},
),
),
);
},
),
您还应该使用FutureBuilder
进行异步调用以获取数据:
FutureBuilder(
future: _getDataFromDatabase(), //async function that returns a Future<Map<String, dynamic>>
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
if (snapshot.connectionState == ConnectionState.done) {
list = [];
}
return CircularProgressIndicator();
}
list = snapshot.data;
return _buildScaffold(); //contains your ListView.builder
});
答案 1 :(得分:0)
布莱恩的答案有很多事情需要考虑。尽管您认为问题中有一部分需要引起注意:
仅当我热重新加载动态小部件时,它才以调试模式加载动态小部件。 应用程序。
这几乎总是表明一旦数据发生更改,您就会丢失setState((){})调用。这意味着发生了更改,但是更改发生后尚未重建UI。即使进行了Brian的更改,您也不会调用setState(尽管如果仅在页面加载时添加一次此数据,那么问题就不多了)。当然可以使用Brian的建议来构建您的UI。 ListView.builder是满足这些类型需求的方法。我的答案是更多,因此,将来在对数据进行更改并且看不到用户界面中反映出任何更改时要考虑的事情。