我正在尝试将Stream从一个选项卡传递到另一个选项卡,但是当我回到家中时。 标签更改后,我可以关闭/销毁流吗? 当应用程序运行时,数据将正确获取且一切正常。仅当我更改选项卡时,问题才会出现。 数据存储到Firestore数据库中。
我收到此错误:
状态不良:流已经被收听
这是我的Home.dart
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
Home createState() => Home();
}
class Home extends State<HomePage> {
int _currentIndex;
var _tabs = [];
List<Company> currentCompaniesList = List();
StreamController<List<Company>> _streamController;
Stream<List<Company>> companiesStream;
_getData() async {
_companyService
.getCompanies()
.then((value) => _streamController.sink.add(value));
}
@override
void initState() {
super.initState();
_currentIndex = 0;
_streamController = StreamController<List<Company>>();
_getData();
companiesStream = _streamController.stream;
}
}
@override
Widget build(BuildContext context) {
_tabs = [
CompanyTab(stream: companiesStream),
MapTab(),
Center(child: Text('Profile')),
Center(child: Text('Settings')),
];
return Scaffold(
...
actions: ...,
body: _tabs[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
backgroundColor: BACKGROUND_COLOR,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
)
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
这是我的CompanyTab.dart
class CompanyTab extends StatefulWidget {
Stream stream;
CompanyTab({Key key, this.stream}) : super(key: key);
@override
_CompanyTabState createState() => _CompanyTabState(stream);
}
class _CompanyTabState extends State<CompanyTab> {
Stream stream;
_CompanyTabState(this.stream);
@override
void initState() {
super.initState();
}
StreamBuilder companyList() {
return StreamBuilder<List<Company>>(
initialData: [],
stream: stream,
builder: (BuildContext context, AsyncSnapshot<List<Company>> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.none ||
snapshot.data == null) {
return LoadingWidget();
} else {
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Company company = snapshot.data.elementAt(index);
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 1.0, horizontal: 4.0),
child: Card(
child: ListTile(
onTap: () {},
title: Text(company.name),
...
),
),
),
);
});
}
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Container(
child: companyList(),
),
);
}
}
答案 0 :(得分:1)
这与小部件的生命周期有关。我可以建议您两个选择。
默认情况下,BottomNavigationBar
会在您离开时破坏标签页
一个并在返回时再次初始化。如果需要的话
您需要移动_streamController
和_getData()
的行为
方法插入_CompanyTabState
中。别忘了打电话
_streamController.close()
方法内的dispose()
_CompanyTabState
,这一点很重要。 _companyService
可以是
注入_CompanyTabState
中。这是一生的时间。
应该像这样工作:
...
class _CompanyTabState extends State<CompanyTab> {
final _streamController = StreamController<List<Company>>();
final CompanyService _companyService;
_CompanyTabState(this._companyService);
@override
void initState() {
super.initState();
_getData();
}
StreamBuilder companyList() {
return StreamBuilder<List<Company>>(
initialData: [],
stream: _streamController.stream,
builder: (BuildContext context, AsyncSnapshot<List<Company>> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.none ||
snapshot.data == null) {
return LoadingWidget();
} else {
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Company company = snapshot.data.elementAt(index);
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 1.0, horizontal: 4.0),
child: Card(
child: ListTile(
onTap: () {},
title: Text(company.name),
...
),
),
),
);
});
}
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Container(
child: companyList(),
),
);
}
@override
void dispose() {
super.dispose();
_streamController.close();
}
void _getData() {
_companyService
.getCompanies()
.then((value) => _streamController.sink.add(value));
}
}
当您离开标签页时,可以保存标签页的状态和小部件数据(例如滚动偏移,输入的文本等)。这是类似iOS UITabBarController的行为。使用IndexedStack实现以下目的:
...
return Scaffold(
...
actions: ...,
body: IndexedStack(
children: _tabs,
index: _currentIndex,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
backgroundColor: BACKGROUND_COLOR,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
),
BottomNavigationBarItem(
...
)
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
要使用哪种选项取决于您,可以根据需要同时使用两者。但是我强烈建议将_streamController移至_CompanyTabState,因为它们的生命周期应该相同。