错误状态:在 flutter 中从 addStream 添加项目时,您无法关闭主题
Bad state: You cannot close the subject while items are being added from addStream in flutter
我正在使用 RxDart 观察变化并相应地更新 UI。当应用程序启动时,我正在进行网络调用并成功获取数据,观察更改并相应地更新 UI。但是当我在关闭屏幕时处理 Subjects
时。它给出以下错误:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (15524): The following StateError was thrown while finalizing the widget tree:
I/flutter (15524): Bad state: You cannot close the subject while items are being added from addStream
这是集团 class:
class MovieDetailBloc {
final _repository = Repository();
final _movieId = PublishSubject<int>();
final _trailers = BehaviorSubject<Future<TrailerModel>>();
Function(int) get fetchTrailersById => _movieId.sink.add;
Observable<Future<TrailerModel>> get movieTrailers => _trailers.stream;
MovieDetailBloc() {
_movieId.stream.transform(_itemTransformer()).pipe(_trailers);
}
dispose() {
_movieId.close();
_trailers.close();
}
_itemTransformer() {
return ScanStreamTransformer(
(Future<TrailerModel> trailer, int id, int index) {
print(index);
trailer = _repository.fetchTrailers(id);
return trailer;
},
);
}
}
这是 UI 屏幕,我在其中调用这些:
import 'dart:async';
import 'package:flutter/material.dart';
import '../blocs/movie_detail_bloc_provider.dart';
import '../models/trailer_model.dart';
class MovieDetail extends StatefulWidget {
final posterUrl;
final description;
final releaseDate;
final String title;
final String voteAverage;
final int movieId;
MovieDetail({
this.title,
this.posterUrl,
this.description,
this.releaseDate,
this.voteAverage,
this.movieId,
});
@override
State<StatefulWidget> createState() {
return MovieDetailState(
title: title,
posterUrl: posterUrl,
description: description,
releaseDate: releaseDate,
voteAverage: voteAverage,
movieId: movieId,
);
}
}
class MovieDetailState extends State<MovieDetail> {
final posterUrl;
final description;
final releaseDate;
final String title;
final String voteAverage;
final int movieId;
MovieDetailBloc bloc;
MovieDetailState({
this.title,
this.posterUrl,
this.description,
this.releaseDate,
this.voteAverage,
this.movieId,
});
@override
void didChangeDependencies() {
bloc = MovieDetailBlocProvider.of(context);
bloc.fetchTrailersById(movieId);
super.didChangeDependencies();
}
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 220.0,
floating: false,
pinned: false,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://image.tmdb.org/t/p/w500$posterUrl",
fit: BoxFit.cover,
)),
),
];
},
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(margin: EdgeInsets.only(top: 5.0)),
Text(
title,
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Row(
children: <Widget>[
Icon(
Icons.favorite,
color: Colors.red,
),
Container(
margin: EdgeInsets.only(left: 1.0, right: 1.0),
),
Text(
voteAverage,
style: TextStyle(
fontSize: 18.0,
),
),
Container(
margin: EdgeInsets.only(left: 10.0, right: 10.0),
),
Text(
releaseDate,
style: TextStyle(
fontSize: 18.0,
),
),
],
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Text(description),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Text(
"Trailer",
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
StreamBuilder(
stream: bloc.movieTrailers,
builder:
(context, AsyncSnapshot<Future<TrailerModel>> snapshot) {
if (snapshot.hasData) {
return FutureBuilder(
future: snapshot.data,
builder:
(context, AsyncSnapshot<TrailerModel> itemSnapShot) {
if (itemSnapShot.hasData) {
if (itemSnapShot.data.results.length > 0)
return trailerLayout(itemSnapShot.data);
else
return noTrailer(itemSnapShot.data);
} else {
return CircularProgressIndicator();
}
},
);
} else {
return CircularProgressIndicator();
}
},
),
],
),
),
),
);
}
Widget noTrailer(TrailerModel data) {
return Center(
child: Container(
child: Text("No trailer available"),
),
);
}
}
Widget trailerLayout(TrailerModel data) {
return Row(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(5.0),
height: 100.0,
color: Colors.grey,
),
Text(
data.results[0].name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
Expanded(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(5.0),
height: 100.0,
color: Colors.grey,
),
Text(
data.results[1].name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
);
}
关闭屏幕时出现错误。 dispose 方法抛出上述异常。我该如何解决这个问题?
我认为排空流应该可以解决问题
dispose() async {
_movieId.close();
await _trailers.drain();
_trailers.close();
}
https://api.dartlang.org/stable/2.0.0/dart-async/Stream-class.html
您也可以解决它替换:
MovieDetailBloc() {
_movieId.stream.transform(_itemTransformer()).pipe(_trailers);
}
和
MovieDetailBloc() {
_movieId.stream.transform(_itemTransformer()).listen((data) {
if (!_categories.isClosed) {
_trailers.add(data);
}
});
}
我正在使用 RxDart 观察变化并相应地更新 UI。当应用程序启动时,我正在进行网络调用并成功获取数据,观察更改并相应地更新 UI。但是当我在关闭屏幕时处理 Subjects
时。它给出以下错误:
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (15524): The following StateError was thrown while finalizing the widget tree:
I/flutter (15524): Bad state: You cannot close the subject while items are being added from addStream
这是集团 class:
class MovieDetailBloc {
final _repository = Repository();
final _movieId = PublishSubject<int>();
final _trailers = BehaviorSubject<Future<TrailerModel>>();
Function(int) get fetchTrailersById => _movieId.sink.add;
Observable<Future<TrailerModel>> get movieTrailers => _trailers.stream;
MovieDetailBloc() {
_movieId.stream.transform(_itemTransformer()).pipe(_trailers);
}
dispose() {
_movieId.close();
_trailers.close();
}
_itemTransformer() {
return ScanStreamTransformer(
(Future<TrailerModel> trailer, int id, int index) {
print(index);
trailer = _repository.fetchTrailers(id);
return trailer;
},
);
}
}
这是 UI 屏幕,我在其中调用这些:
import 'dart:async';
import 'package:flutter/material.dart';
import '../blocs/movie_detail_bloc_provider.dart';
import '../models/trailer_model.dart';
class MovieDetail extends StatefulWidget {
final posterUrl;
final description;
final releaseDate;
final String title;
final String voteAverage;
final int movieId;
MovieDetail({
this.title,
this.posterUrl,
this.description,
this.releaseDate,
this.voteAverage,
this.movieId,
});
@override
State<StatefulWidget> createState() {
return MovieDetailState(
title: title,
posterUrl: posterUrl,
description: description,
releaseDate: releaseDate,
voteAverage: voteAverage,
movieId: movieId,
);
}
}
class MovieDetailState extends State<MovieDetail> {
final posterUrl;
final description;
final releaseDate;
final String title;
final String voteAverage;
final int movieId;
MovieDetailBloc bloc;
MovieDetailState({
this.title,
this.posterUrl,
this.description,
this.releaseDate,
this.voteAverage,
this.movieId,
});
@override
void didChangeDependencies() {
bloc = MovieDetailBlocProvider.of(context);
bloc.fetchTrailersById(movieId);
super.didChangeDependencies();
}
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
expandedHeight: 220.0,
floating: false,
pinned: false,
flexibleSpace: FlexibleSpaceBar(
background: Image.network(
"https://image.tmdb.org/t/p/w500$posterUrl",
fit: BoxFit.cover,
)),
),
];
},
body: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(margin: EdgeInsets.only(top: 5.0)),
Text(
title,
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Row(
children: <Widget>[
Icon(
Icons.favorite,
color: Colors.red,
),
Container(
margin: EdgeInsets.only(left: 1.0, right: 1.0),
),
Text(
voteAverage,
style: TextStyle(
fontSize: 18.0,
),
),
Container(
margin: EdgeInsets.only(left: 10.0, right: 10.0),
),
Text(
releaseDate,
style: TextStyle(
fontSize: 18.0,
),
),
],
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Text(description),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
Text(
"Trailer",
style: TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
),
),
Container(margin: EdgeInsets.only(top: 8.0, bottom: 8.0)),
StreamBuilder(
stream: bloc.movieTrailers,
builder:
(context, AsyncSnapshot<Future<TrailerModel>> snapshot) {
if (snapshot.hasData) {
return FutureBuilder(
future: snapshot.data,
builder:
(context, AsyncSnapshot<TrailerModel> itemSnapShot) {
if (itemSnapShot.hasData) {
if (itemSnapShot.data.results.length > 0)
return trailerLayout(itemSnapShot.data);
else
return noTrailer(itemSnapShot.data);
} else {
return CircularProgressIndicator();
}
},
);
} else {
return CircularProgressIndicator();
}
},
),
],
),
),
),
);
}
Widget noTrailer(TrailerModel data) {
return Center(
child: Container(
child: Text("No trailer available"),
),
);
}
}
Widget trailerLayout(TrailerModel data) {
return Row(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(5.0),
height: 100.0,
color: Colors.grey,
),
Text(
data.results[0].name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
Expanded(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.all(5.0),
height: 100.0,
color: Colors.grey,
),
Text(
data.results[1].name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
);
}
关闭屏幕时出现错误。 dispose 方法抛出上述异常。我该如何解决这个问题?
我认为排空流应该可以解决问题
dispose() async {
_movieId.close();
await _trailers.drain();
_trailers.close();
}
https://api.dartlang.org/stable/2.0.0/dart-async/Stream-class.html
您也可以解决它替换:
MovieDetailBloc() {
_movieId.stream.transform(_itemTransformer()).pipe(_trailers);
}
和
MovieDetailBloc() {
_movieId.stream.transform(_itemTransformer()).listen((data) {
if (!_categories.isClosed) {
_trailers.add(data);
}
});
}