Flutter StreamBuilder 刷新屏幕,更新列表数据来自 API
Flutter StreamBuilder Refresh Screen with updated list data from API
我正在尝试将我的应用程序转换为以三秒为周期定期使用 streamBuilder。
但是,我现在以错误告终。
错误状态:流已被收听。
请注意,我在屏幕上使用两个列表视图来显示活动和非活动作业。
这是从请求到流的代码。
List<Ticket> sortedListAwaiting = [];
List<Ticket> sortedListActive = [];
Future<List<Ticket>> getAssignedAwaitingTickets() async {
client.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
HttpClientRequest request =
await client.getUrl(Uri.parse("$emulatorHost/Jobs"));
request.headers.add("Authorization", "Bearer " + jwt);
HttpClientResponse result = await request.close();
if (result.statusCode == 200) {
List<dynamic> jsonData =
jsonDecode(await result.transform(utf8.decoder).join());
if (sortedListAwaiting.isNotEmpty) {
sortedListAwaiting.clear();
for (var i in jsonData) {
if (i['status'] == "Ready-To-Start" &&
i['staffName'] == name.toLowerCase()) {
sortedListAwaiting.add(new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
));
}
}
} else {
for (var i in jsonData) {
if (i['status'] == "Ready-To-Start" &&
i['staffName'] == name.toLowerCase()) {
sortedListAwaiting.add(
new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
),
);
}
}
}
}
return sortedListAwaiting;
}
Stream<List<Ticket>> getSortedListAwaiting() =>
Stream.periodic(Duration(seconds: 3))
.asyncMap((event) => getAssignedAwaitingTickets());
Future<List<Ticket>> getAssignedActiveTickets() async {
client.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
HttpClientRequest request =
await client.getUrl(Uri.parse("$emulatorHost/Jobs"));
request.headers.add("Authorization", "Bearer " + jwt);
HttpClientResponse result = await request.close();
if (result.statusCode == 200) {
List<dynamic> jsonData =
jsonDecode(await result.transform(utf8.decoder).join());
if (sortedListActive.isNotEmpty) {
sortedListActive.clear();
for (var i in jsonData) {
if (i['status'] == "In-Route" && i['staffName'] == name.toLowerCase()) {
sortedListActive.add(new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
));
}
}
} else {
for (var i in jsonData) {
if (i['status'] == "In-Route" && i['staffName'] == name.toLowerCase()) {
sortedListActive.add(
new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
),
);
}
}
}
}
return sortedListActive;
}
Stream<List<Ticket>> getSortedListActive() =>
Stream.periodic(Duration(seconds: 3))
.asyncMap((event) => getAssignedAwaitingTickets());
第一个列表视图
TabBarView(
children: [
Center(
child: Padding(
padding: EdgeInsets.only(left: 18, right: 18),
child: SingleChildScrollView(
child: Column(
children: [
Row(
children: [
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
"Active",
),
),
],
),
StreamBuilder<List<Ticket>>(
stream: getSortedListActive(),
builder: (context,
AsyncSnapshot<List<Ticket>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return CircularProgressIndicator();
}
if (snapshot.hasData) {
return Container(
margin: EdgeInsets.only(top: 20),
height: 240,
child: ListView.builder(
itemBuilder: (context, index) {
return Padding(
padding:
const EdgeInsets.only(bottom: 16.0),
child: GestureDetector(
onTap: () async {
await getSpecificJob(
activeJobTickets[index].JobID);
await getLatLng(
sortedListActive[index]
.jobAddress);
print(
activeJobTickets[index].JobID);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
TicketScreen(
activeJobTickets[index].JobID,
activeJobTickets[index]
.staffName,
activeJobTickets[index]
.clientName,
activeJobTickets[index]
.jobName,
activeJobTickets[index]
.jobAddress,
activeJobTickets[index]
.clientContact,
activeJobTickets[index]
.jobDescription,
activeJobTickets[index]
.jobDate,
activeJobTickets[index]
.jobTime,
activeJobTickets[index]
.status,
),
),
);
},
child: newTicketWidget(
sortedListActive[index].jobName,
sortedListActive[index]
.jobDescription,
sortedListActive[index].jobAddress,
sortedListActive[index].staffName,
sortedListActive[index].jobDate,
sortedListActive[index].jobTime,
),
),
);
},
itemCount: sortedListActive.length,
),
);
}
return CircularProgressIndicator();
}),
第二个列表视图
StreamBuilder<List<Ticket>>(
stream: getSortedListAwaiting(),
builder:
(context, AsyncSnapshot<List<Ticket>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return CircularProgressIndicator();
}
if (snapshot.hasData) {
return Container(
margin: EdgeInsets.only(top: 20),
height: 240,
child: ListView.builder(
itemBuilder: (context, index) {
return Padding(
padding:
const EdgeInsets.only(bottom: 16.0),
child: GestureDetector(
onTap: () async {
getSpecificJob(
awaitingJobTickets[index].JobID);
await getLatLng(
sortedListAwaiting[index]
.jobAddress);
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => TicketScreen(
sortedListAwaiting[index].JobID,
sortedListAwaiting[index]
.staffName,
sortedListAwaiting[index]
.clientName,
sortedListAwaiting[index]
.jobName,
sortedListAwaiting[index]
.jobAddress,
sortedListAwaiting[index]
.clientContact,
sortedListAwaiting[index]
.jobDescription,
sortedListAwaiting[index]
.jobDate,
sortedListAwaiting[index]
.jobTime,
sortedListAwaiting[index]
.status),
));
},
child: newTicketWidget(
sortedListAwaiting[index].jobName,
sortedListAwaiting[index]
.jobDescription,
sortedListAwaiting[index].jobAddress,
sortedListAwaiting[index].staffName,
sortedListAwaiting[index].jobDate,
sortedListAwaiting[index].jobTime,
),
),
);
},
itemCount: sortedListAwaiting.length,
),
);
}
return CircularProgressIndicator();
},
),
我对使用 StreamBuilder 完全陌生,我通常只单独使用 listview.builder,但现在我需要数据每三秒刷新一次。因此,任何指南、解释和示例都将非常感激。
提前为开发者干杯。
编辑
我被告知尝试将流添加到 var 并将其设置为 innit 状态但是我仍然有错误
late Stream<List<Ticket>> myPeriodicStream;
late Stream<List<Ticket>> myPeriodicStream1;
@override
void initState() {
refreshLists();
super.initState();
myPeriodicStream = getSortedListActive();
myPeriodicStream1 = getSortedListAwaiting();
}
问题不在于流,而在于选项卡控制器。我通过反复试验发现了这一点,并得出结论,问题出在 DefaultTabBarController。一旦我删除了 DefaultTabController,流就不会处于错误状态。解决方法可能是找出一种在处理方法中处理控制器的方法。但是,我改用底部导航栏并使用栏的索引来更改页面
我正在尝试将我的应用程序转换为以三秒为周期定期使用 streamBuilder。 但是,我现在以错误告终。 错误状态:流已被收听。 请注意,我在屏幕上使用两个列表视图来显示活动和非活动作业。 这是从请求到流的代码。
List<Ticket> sortedListAwaiting = [];
List<Ticket> sortedListActive = [];
Future<List<Ticket>> getAssignedAwaitingTickets() async {
client.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
HttpClientRequest request =
await client.getUrl(Uri.parse("$emulatorHost/Jobs"));
request.headers.add("Authorization", "Bearer " + jwt);
HttpClientResponse result = await request.close();
if (result.statusCode == 200) {
List<dynamic> jsonData =
jsonDecode(await result.transform(utf8.decoder).join());
if (sortedListAwaiting.isNotEmpty) {
sortedListAwaiting.clear();
for (var i in jsonData) {
if (i['status'] == "Ready-To-Start" &&
i['staffName'] == name.toLowerCase()) {
sortedListAwaiting.add(new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
));
}
}
} else {
for (var i in jsonData) {
if (i['status'] == "Ready-To-Start" &&
i['staffName'] == name.toLowerCase()) {
sortedListAwaiting.add(
new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
),
);
}
}
}
}
return sortedListAwaiting;
}
Stream<List<Ticket>> getSortedListAwaiting() =>
Stream.periodic(Duration(seconds: 3))
.asyncMap((event) => getAssignedAwaitingTickets());
Future<List<Ticket>> getAssignedActiveTickets() async {
client.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
HttpClientRequest request =
await client.getUrl(Uri.parse("$emulatorHost/Jobs"));
request.headers.add("Authorization", "Bearer " + jwt);
HttpClientResponse result = await request.close();
if (result.statusCode == 200) {
List<dynamic> jsonData =
jsonDecode(await result.transform(utf8.decoder).join());
if (sortedListActive.isNotEmpty) {
sortedListActive.clear();
for (var i in jsonData) {
if (i['status'] == "In-Route" && i['staffName'] == name.toLowerCase()) {
sortedListActive.add(new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
));
}
}
} else {
for (var i in jsonData) {
if (i['status'] == "In-Route" && i['staffName'] == name.toLowerCase()) {
sortedListActive.add(
new Ticket(
i['jobID'],
i['staffName'],
i['clientName'],
i['jobName'],
i['jobAddress'],
i['clientContact'],
i['jobDescription'],
i['jobDate'],
i['jobTime'],
i['status'],
i['isEditing'],
),
);
}
}
}
}
return sortedListActive;
}
Stream<List<Ticket>> getSortedListActive() =>
Stream.periodic(Duration(seconds: 3))
.asyncMap((event) => getAssignedAwaitingTickets());
第一个列表视图
TabBarView(
children: [
Center(
child: Padding(
padding: EdgeInsets.only(left: 18, right: 18),
child: SingleChildScrollView(
child: Column(
children: [
Row(
children: [
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
"Active",
),
),
],
),
StreamBuilder<List<Ticket>>(
stream: getSortedListActive(),
builder: (context,
AsyncSnapshot<List<Ticket>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return CircularProgressIndicator();
}
if (snapshot.hasData) {
return Container(
margin: EdgeInsets.only(top: 20),
height: 240,
child: ListView.builder(
itemBuilder: (context, index) {
return Padding(
padding:
const EdgeInsets.only(bottom: 16.0),
child: GestureDetector(
onTap: () async {
await getSpecificJob(
activeJobTickets[index].JobID);
await getLatLng(
sortedListActive[index]
.jobAddress);
print(
activeJobTickets[index].JobID);
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
TicketScreen(
activeJobTickets[index].JobID,
activeJobTickets[index]
.staffName,
activeJobTickets[index]
.clientName,
activeJobTickets[index]
.jobName,
activeJobTickets[index]
.jobAddress,
activeJobTickets[index]
.clientContact,
activeJobTickets[index]
.jobDescription,
activeJobTickets[index]
.jobDate,
activeJobTickets[index]
.jobTime,
activeJobTickets[index]
.status,
),
),
);
},
child: newTicketWidget(
sortedListActive[index].jobName,
sortedListActive[index]
.jobDescription,
sortedListActive[index].jobAddress,
sortedListActive[index].staffName,
sortedListActive[index].jobDate,
sortedListActive[index].jobTime,
),
),
);
},
itemCount: sortedListActive.length,
),
);
}
return CircularProgressIndicator();
}),
第二个列表视图
StreamBuilder<List<Ticket>>(
stream: getSortedListAwaiting(),
builder:
(context, AsyncSnapshot<List<Ticket>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return CircularProgressIndicator();
}
if (snapshot.hasData) {
return Container(
margin: EdgeInsets.only(top: 20),
height: 240,
child: ListView.builder(
itemBuilder: (context, index) {
return Padding(
padding:
const EdgeInsets.only(bottom: 16.0),
child: GestureDetector(
onTap: () async {
getSpecificJob(
awaitingJobTickets[index].JobID);
await getLatLng(
sortedListAwaiting[index]
.jobAddress);
Navigator.of(context)
.push(MaterialPageRoute(
builder: (context) => TicketScreen(
sortedListAwaiting[index].JobID,
sortedListAwaiting[index]
.staffName,
sortedListAwaiting[index]
.clientName,
sortedListAwaiting[index]
.jobName,
sortedListAwaiting[index]
.jobAddress,
sortedListAwaiting[index]
.clientContact,
sortedListAwaiting[index]
.jobDescription,
sortedListAwaiting[index]
.jobDate,
sortedListAwaiting[index]
.jobTime,
sortedListAwaiting[index]
.status),
));
},
child: newTicketWidget(
sortedListAwaiting[index].jobName,
sortedListAwaiting[index]
.jobDescription,
sortedListAwaiting[index].jobAddress,
sortedListAwaiting[index].staffName,
sortedListAwaiting[index].jobDate,
sortedListAwaiting[index].jobTime,
),
),
);
},
itemCount: sortedListAwaiting.length,
),
);
}
return CircularProgressIndicator();
},
),
我对使用 StreamBuilder 完全陌生,我通常只单独使用 listview.builder,但现在我需要数据每三秒刷新一次。因此,任何指南、解释和示例都将非常感激。 提前为开发者干杯。
编辑 我被告知尝试将流添加到 var 并将其设置为 innit 状态但是我仍然有错误
late Stream<List<Ticket>> myPeriodicStream;
late Stream<List<Ticket>> myPeriodicStream1;
@override
void initState() {
refreshLists();
super.initState();
myPeriodicStream = getSortedListActive();
myPeriodicStream1 = getSortedListAwaiting();
}
问题不在于流,而在于选项卡控制器。我通过反复试验发现了这一点,并得出结论,问题出在 DefaultTabBarController。一旦我删除了 DefaultTabController,流就不会处于错误状态。解决方法可能是找出一种在处理方法中处理控制器的方法。但是,我改用底部导航栏并使用栏的索引来更改页面