【发布时间】:2019-08-24 23:36:00
【问题描述】:
我有一个带有 tabBarView 的主页,有 2 个页面,主页和收藏夹。主页有一个gridview,其单元格由streambuilder 填充。单击时,他们使用导航器重定向到该单元格的详细信息页面。我可以在 2 个标签页之间切换。转到详细信息页面(从主页)并返回主页后,gridView 会正确显示其数据。但在那之后,如果我转到收藏夹页面并返回主页,gridView 的数据就会丢失。
我已经按照 SO 上的建议尝试了 AutomaticKeepAliveClientMixin 和 wantKeepAlive = true。
根据调试器,在主页小部件和收藏夹之间切换时,主页小部件不会重建,并且数据显示正常。
从详细信息页面返回主页确实会重建主页,这在数据显示时也很好。只有在那之后我转到收藏夹选项卡并再次返回时才会出现问题。
我正在使用 bloc 模式,并在 home 小部件中引用了 Provider 的 bloc。它将这个传递给gridView。
我在 SliverAppBar 中使用标准 tabBarView 和 Navigator。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MovieProvider(
euCollBloc: EuThemeCollectionBloc(API()),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(),
home: MyHomePage(),
),
);
}
}
body: TabBarView(
children: <Widget>[
PageOne(),
PageTwo(),
],
bottom: TabBar(
tabs: <Widget>[
Tab(
text: "Home",
icon: Icon(Icons.home),
),
Tab(
text: "Favorites",
icon: Icon(Icons.favorite),
),
],
controller: _tabController,
))
.......
导航器,用于 PageOne 小部件:
.......
return GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: snapshot.data.length,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EuroCard(
preview: snapshot.data[index].preview ?? "",
title: snapshot.data[index].title,
description: snapshot.data[index].description,
),
));
},
child: Card(
.......
使用 youtube 上 tensor 的教程中的提供程序和块代码(对我来说可能太高级了)。
集团:
class EuThemeCollectionBloc {
final API api;
Stream<List<EuThemeCollection>> _results = Stream.empty();
Stream<String> _log = Stream.empty();
ReplaySubject<String> _query = ReplaySubject<String>();
Stream<String> get log => _log;
Stream<List<EuThemeCollection>> get results => _results;
Sink<String> get query => _query;
EuThemeCollectionBloc(this.api) {
_results = _query.distinct().asyncMap(api.get).asBroadcastStream();
_log = Observable(results)
.withLatestFrom(_query.stream, (_, query) => 'Results for $query')
.asBroadcastStream();
}
void dispose() {
_query.close();
}
}
提供者:
class MovieProvider extends InheritedWidget {
final EuThemeCollectionBloc euCollBloc;
@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static EuThemeCollectionBloc of(BuildContext context) =>
(context.inheritFromWidgetOfExactType(MovieProvider) as MovieProvider)
.euCollBloc;
MovieProvider({Key key, EuThemeCollectionBloc euCollBloc, Widget child})
: this.euCollBloc = euCollBloc ?? EuThemeCollectionBloc(API()),
super(child: child, key: key);
}
我尝试使用 BehaviorSubject,但在主页面中引用查询流时出现运行时错误:
错误:没有为类“EuroCard”定义吸气剂“euCollBloc”。 - “EuroCard”来自“package:bloc_example/euroCard.dart”(“lib/euroCard.dart”)。 尝试将名称更正为现有 getter 的名称,或定义名为“euCollBloc”的 getter 或字段。
固定: 我需要将 super.build(context) 添加到 PageOne (GridView) 小部件 - 它使用 AutomaticKeepAliveClientMixin 扩展状态,因此需要被覆盖。抱歉,最初甚至没有发布罪魁祸首部分。
class _PageOneState extends State<PageOne> with
AutomaticKeepAliveClientMixin<PageOne>{
@override
bool get wantKeepAlive => true;
Widget build(BuildContext context){
super.build(context);
var euCollBloc = MovieProvider.of(context);
【问题讨论】:
-
给个代码示例而不是解释就好了!
-
似乎没有设置默认值。您可能需要考虑使用
BehaviorSubject,即使没有数据发送到流来触发构建,它也会保留以前的值。但是一些代码会有所帮助。 -
感谢您的回复,我已添加代码。 (尝试了 BehaviorSubject,并得到关于未定义查询的 getter 的错误。)。希望有任何见解。