Reputation: 4832
I am using this flutter library to handle notifications. In the initState()
in my HomeView
I initialize this listener:
_notificationsActionStreamSubscription = AwesomeNotifications().actionStream.listen((receivedNotification) {
print("user tapped on notification " + receivedNotification.id.toString());
});
Later when someone logs in or signs out of my app I call these lines:
Navigator.of(context).popUntil((route) => route.isFirst);
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => HomeView()));
This let's the initState()
of my HomeView
be called again which results in the error:
Bad state: Stream has already been listened to.
That is why I did this before calling the two Navigator lines from above, but without success:
AwesomeNotifications().createdSink.close();
_notificationsActionStreamSubscription.cancel();
What am I doing wrong? I cancel the streamsubscription so why do I still get this error message?
Thanks for your advice!
Upvotes: 9
Views: 3175
Reputation: 524
Move the listeners to the initState method of the class. Suppose you were listening from the build method of the material app widget.
Instead of :
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
// Listener
AwesomeNotifications().actionStream().listen((event) {});
//
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
Do this:
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
AwesomeNotifications().actionStream().listen((event) {});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
Upvotes: 0
Reputation: 817
According to the docs, the listeners should be a top-level function and implemented in the main.dart file. You should basically move all the listeners to a different function or class and then call it in the main function
void main(){
WidgetsFlutterBinding.ensureInitialized();
notificationInit();
runApp(MaterialApp(home: YourApp()));
}
void notificationInit() async {
await AwesomeNotifications.initialize(...);
_notificationsActionStreamSubscription = ...;
_notificationsCreatedStreamSubscription = ...;
_notificationsDisplayedStreamSubscription = ...;
_notificationsDismissedStreamSubscription = ...;
}
Upvotes: 3
Reputation: 3300
The error you get is not caused by _notificationsActionStreamSubscription
.
If you read carefully it says
Stream has already been listened to
That means that probably AwesomeNotifications().actionStream
can only handle one listener at a time.
_notificationsActionStreamSubscription.cancel()
doesn't seem to work, it is possible that AwesomeNotifications().actionStream
doesn't know that the stream listener has been closed.
Every time the page get pushed, it is rebuilt, and AwesomeNotifications()
throw an error becouse it thinks that you are attacching a second listener.
So I came with this solution: Move the notificationsActionStreamSubscription
to a widget which is parent to HomeView
.
Create the instance right there in the parent, and then attach it to the actionStream.
Every time you call Navigator.pushReplacement
send it as a parameter.
HomeView: (I made it a statefullwidget)
class HomeView extends StatefulWidget {
final StreamSubscription<ReceivedAction> notificationsActionStreamSubscription;
const HomeView({Key key, @required this.notificationsActionStreamSubscription}) : super(key: key);
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
//You can access with widget.notificationsActionStreamSubscription
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('HomeView '),
),
body: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [],
)
],
),
),
);
}
}
In your parent widget (I suppose it is a statefull widget):
StreamSubscription<ReceivedAction> notificationsActionStreamSubscription;
@override
void initState() {
super.initState();
notificationsActionStreamSubscription =
AwesomeNotifications().actionStream.listen((receivedNotification) {
print(
"user tapped on notification " + receivedNotification.id.toString());
});
}
And every time you push the HomeView:
Navigator.of(context).popUntil((route) => route.isFirst);
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => HomeView(notificationsActionStreamSubscription:
notificationsActionStreamSubscription)));
By doing so, notificationsActionStreamSubscription
will not be rebuilt and attached to AwesomeNotifications().actionStream
every time you push the HomeView
.
Upvotes: 1