I have read some othe questions about this topic but I'm quite new in Flutter and I don't know how exactly I've to do in my case.
When my app is in background, the notifications are shown twice, but they have one difference. One of them has the icon I designed but the other shows the default white square icon.
This is my code:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
flutterLocalNotificationsPlugin.show(
message.notification.hashCode,
message.notification?.title,
message.notification?.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
icon: '#mipmap/icon',
),
),
);
}
const AndroidNotificationChannel channel=AndroidNotificationChannel(
'high_importance_channel',//id
'Hig Importance Notification',//name
'This channel is used', //description
importance: Importance.high,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin=FlutterLocalNotificationsPlugin();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
// Replace with actual values
options: FirebaseOptions(
//apiKey: "",
apiKey: "",
appId: "",
messagingSenderId: "",
projectId: "",
storageBucket: "",
),
);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
runApp(Portada());
}
class Portada extends StatelessWidget {
const Portada({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: "ATGapp",
home:Inicio(),
);
}
}
class Inicio extends StatefulWidget {
Inicio({Key? key}) : super(key: key);
#override
///
_InicioState createState() => _InicioState();
}
class _InicioState extends State<Inicio> {
final FirebaseMessaging _firebaseMessaging=FirebaseMessaging.instance;
#override
late StreamSubscription<User?> user;
void initState() {
getImage(path);
torneoactual();
super.initState();
var initializationSettingsAndroid=
AndroidInitializationSettings('#mipmap/icon');
var initializationSettings=
InitializationSettings(android: initializationSettingsAndroid);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Handling a otro message ${message.messageId}');
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
icon: '#mipmap/icon',
),
),
);
}
});
_firebaseMessaging.getToken().then((value) {
print(value);
tokini=value.toString();
buscatoken(tokini);
});
}
I've read something about the difference between notification and data and this is probably my problem, but I don't know how to solve it.
Than you in advance.
Related
App is crashing a lot while starting it.
In my app, I am using Crashlytics to log the errors.
As I can see in Crashlytics, users are getting below errors and app is unresponsive.
Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Null check operator used on a null value. Error thrown null.
at State.setState(framework.dart:1141)
at _PlatformViewLinkState._onPlatformViewCreated(platform_view.dart:898)
at AndroidViewController.create(platform_views.dart:775)
Seems like this error is getting occured on app load only.
main.dart file
import 'dart:async';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:my_app/Home_screen.dart';
import 'package:my_app/utils/helpers/admob_helper.dart';
import 'package:my_app/utils/helpers/interstitial_ad_helper.dart';
import 'package:my_app/utils/helpers/notification_helper.dart';
import 'package:my_app/widgets/shared/rate_my_app.dart';
import 'config/theme_config.dart';
import 'utils/helpers/dark_theme_listener.dart';
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.high,
playSound: true,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('A bg message just showed up : ${message.messageId}');
}
Future<void> main() async {
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.instance.subscribeToTopic(
"ScratchNotiftest"); //Replace with JHNotifTest for Live
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
AdmobHelper.initialize();
await new ThemeHelper().initialize();
InterstitialAdHelper.calculateNextAdDisplay();
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError;
runApp(MyApp());
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(statusBarColor: Color(0xff004175)));
}, (Object error, StackTrace stack) {
FirebaseCrashlytics.instance.recordError(error, stack);
});
}
class MyApp extends StatefulWidget {
MyApp({
Key? key,
}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification!;
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: NotificationHelper.getAndroidNotificationDetails(channel),
));
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
RemoteNotification notification = message.notification!;
showDialog(
context: context,
builder: (_) {
return AlertDialog(
title: Text(notification.title ?? 'my_app'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Text(notification.body ?? 'New Notification')],
),
),
);
});
});
}
#override
Widget build(BuildContext context) {
// Only call clearSavedSettings() during testing to reset internal values.
// Upgrader().clearSavedSettings(); // REMOVE this for release builds
return ValueListenableBuilder<bool>(
valueListenable: isDark,
builder: (ctx, theme, child) => MaterialApp(
themeMode: theme ? ThemeMode.dark : ThemeMode.light,
debugShowCheckedModeBanner: false,
title: 'my_app',
theme: lightThemeData(context),
darkTheme: darkThemeData(context),
home: RateAppInitWidget(
builder: (rateMyApp) => HomeScreen(
rateMyApp: rateMyApp,
),
),
),
);
}
}
My Qestions:
Is there anything wrong in my main.dart file?
If flutter is null safe, then why it is breaking? (Again if bang operator is not that safe to use, why it is getting used everywhere).
I really appricate any help. Thanks in advance.
Try Removing the ! from this line & Pass Some Default Value for RemoteNotification Type:
RemoteNotification notification = message.notification!;
I'm trying in Android to show a local notification as a test, everything works fine if the app is foreground and background, but I need the notification to show when the app is terminated, which is this mode (when I terminate the app) workmanager doesn't work .
I have seen many questions and answers but I have not found anything clear, does anyone know how to make the notification appear when the application is finished? I don't want to use push notifications or Fcm, I know that, but I need to know how to do this locally.
my main.dart
I'm trying to show a local notification as a test, everything works fine if the app is foreground and background, but I need the notification to show when the app is terminated, which is this mode (when I terminate the app) workmanager doesn't work .
I have seen many questions and answers but I have not found anything clear, does anyone know how to make the notification appear when the application is finished? I don't want to use push notifications or Fmc, I know that, but I need to know how to do this locally.
my main.dart
import 'package:flutter/material.dart';
import 'package:workmanager/workmanager.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
void callbackDispatcher() {
Workmanager.executeTask((task, inputData) async {
if (task == 'uniqueKey') {
///do the task in Backend for how and when to send notification
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails('your channel id', 'your channel name',
'your channel description',
importance: Importance.max,
priority: Priority.high,
showWhen: false);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'hello',
'1245',
platformChannelSpecifics,
payload: 'item x');
}
return Future.value(true);
});
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
Workmanager.initialize(
callbackDispatcher,
isInDebugMode:
true);
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings(
'#mipmap/ic_launcher');
final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings();
final MacOSInitializationSettings initializationSettingsMacOS =
MacOSInitializationSettings();
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: initializationSettingsMacOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: selectNotification);
runApp(const MyApp());
}
Future selectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
}
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Work manager Example"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
Workmanager.registerPeriodicTask(
"1",
"uniqueKey",
frequency: Duration(minutes: 15),
initialDelay: Duration(seconds:10),
);
print('START');
},
child: Text("Run Task")),
SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {
Workmanager.cancelByUniqueName("1");
print('cancel');
},
child: Text("Cancel Task"))
],
),
),
);
}
#override
void initState() {
// TODO: implement initState
super.initState();
}
}
I want the user to land to a specific screen when a notification is tapped from a terminated state. I know that the getInitialMessage() handles notifications from terminated state but it doesn't seem to navigate to the screen I want.
Here's the code:
AndroidNotificationChannel channel;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: "Main Navigator");
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
RemoteNotification notification = message.notification;
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
icon: '#drawable/splash',
playSound: true
),
));
navigatorKey.currentState
.push(MaterialPageRoute(builder: (_) => OrdersScreen()));
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.high,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
void initState() {
var initializationSettingsAndroid = AndroidInitializationSettings('#drawable/splash');
var initializationSettings = InitializationSettings(android:initializationSettingsAndroid);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
print('Inside get initial message');
if (message != null) {
print('Inside message not null');
navigatorKey.currentState
.push(MaterialPageRoute(builder: (_) => OrdersScreen()));
}
});
}
}
As you can see, I want to navigate to ordersscreen but I instead land on the landing page. What am I missing? It works fine when the notification is tapped from background state or foreground state, but not from terminated state.
I tried the official documentation and also tried following a lot of different guides but somehow i am unable to be able to show a simple local notification on my app. I am confused with completely different lines of code being shown on different guides. My app runs fine without the local notification implementation.
It is a simple app which fetches some data from an API and should display a notification whenever any of the computed data is > 0.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future main() async {
//WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MyWin App',
theme: ThemeData.dark(
//primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'CoWin paid vaccine availability for 18+'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('icons8_coronavirus_64.png');
final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings();
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: null);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: selectNotification);
fetchAvailability();
getData();
}
Future selectNotification(String payload) async {
//Handle notification tapped logic here
}
int day = 0;
int sumApolloGariahat = 0;
int sumApolloBypass = 0;
int sumWoodlands = 0;
List<int> availableAtApolloBypass = [];
List<int> availableAtApolloGariahat = [];
List<int> availableAtWoodlands = [];
var url = Uri.parse(
'https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/calendarByDistrict?district_id=725&date=17-05-2021');
Future<http.Response> fetchAvailability() {
return http.get(url);
}
Future getData() async {
var response = await http.get(url);
if (response.statusCode == 200) {
String data = response.body;
Map decodedData = jsonDecode(data);
var apolloGariahatID = decodedData['centers'][11]['center_id'];
var apolloBypassID = decodedData['centers'][16]['center_id'];
var woodlandsID = decodedData['centers'][23]['center_id'];
for (day = 0;
day < decodedData['centers'][12]['sessions'].length;
day++) {
availableAtApolloGariahat.add(decodedData['centers'][12]['sessions']
[day]['available_capacity_dose1']);
}
for (day = 0;
day < decodedData['centers'][16]['sessions'].length;
day++) {
availableAtApolloBypass.add(decodedData['centers'][16]['sessions'][day]
['available_capacity_dose1']);
}
for (day = 0;
day < decodedData['centers'][27]['sessions'].length;
day++) {
availableAtWoodlands.add(decodedData['centers'][27]['sessions'][day]
['available_capacity_dose1']);
}
availableAtApolloGariahat.forEach((e) => sumApolloGariahat += e);
availableAtApolloBypass.forEach((e) => sumApolloBypass += e);
availableAtWoodlands.forEach((e) => sumWoodlands += e);
print('Available at Apollo Gariahat: $sumApolloGariahat');
print('Available at Apollo EM Bypass: $sumApolloBypass');
print('Available at Woodlands: $sumWoodlands');
} else {
print(response.statusCode);
}
}
Future showNotification() async {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'your channel id', 'your channel name', 'your channel description',
importance: Importance.max,
priority: Priority.high,
showWhen: false);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0, 'plain title', 'plain body', platformChannelSpecifics,
payload: 'item x');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Available at Apollo Gariahat: $sumApolloGariahat',
style: TextStyle(fontSize: 20.0),
),
Text(
'Available at Apollo EM Bypass: $sumApolloBypass',
style: TextStyle(fontSize: 20.0),
),
Text(
'Available at Woodlands: $sumWoodlands',
style: TextStyle(fontSize: 20.0),
),
TextButton(
onPressed: showNotification,
child: Text('Show Notification'),
),
],
),
),
);
}
}
I think there is an issue with the initialisation of your plugin.
You have given your android settings as this.
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('icons8_coronavirus_64.png');
You have probably forgot to include this image asset directly in the android/app/src/main/res/drawable folder.
As mentioned in the documentation of flutter_local_notifications, for showing notification on android, all images need to be added into the drawable folder.
I have added my own icon.png into the drawable folder like this,
The, I used it in my initialization, like this
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('icon.png');
This fixed the issue for me and I can now see your sample notification.
I noticed something strange, quite probably because maybe I don't understand the concept.
I am listening to cloud message from firebase. I have 2 dart files A and B.
A looks like:
import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
FirebaseMessaging firebaseMessaging = new FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
#override
void initState() {
super.initState();
firebaseMessaging.configure(
onLaunch: (Map<String, dynamic> msg) {
print(" onLaunch called $msg");
},
onResume: (Map<String, dynamic> msg) {
print(" onResume called ${(msg)}");
},
onMessage: (Map<String, dynamic> msg) {
//showNotification(msg);
print(" onMessage called in Activity A ${(msg)}");//--!!!!!-------!!!!->notice this
},
);
firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound: true, alert: true, badge: true));
firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings setting) {
print('IOS Setting Registered');
});
firebaseMessaging.getToken().then((token) {
print("token: "+token);
});
flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
var android = new AndroidInitializationSettings('#mipmap/ic_launcher');
var iOS = new IOSInitializationSettings();
var initSetttings = new InitializationSettings(android, iOS);
flutterLocalNotificationsPlugin.initialize(initSetttings);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>Sample() ));// calling screen B from action of app bar
},
)
],
),
body: new Container(),
);
}
}
Notice the line where I print in console if a new message is called in "Activity A"..
Now B looks like:
import 'package:flutter/material.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class Sample extends StatefulWidget {
#override
_SampleState createState() => _SampleState();
}
class _SampleState extends State<Sample> {
#override
void dispose(){
super.dispose();
}
FirebaseMessaging firebaseMessaging1 = new FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin1;
#override
void initState() {
super.initState();
firebaseMessaging1.configure(
onLaunch: (Map<String, dynamic> msg) {
print(" onLaunch called $msg");
},
onResume: (Map<String, dynamic> msg) {
print(" onResume called ${(msg)}");
},
onMessage: (Map<String, dynamic> msg) {
//showNotification(msg);
print(" onMessage called in Activity B ${(msg)}");//----!!!---!!!!---Notice this
},
);
firebaseMessaging1.requestNotificationPermissions(
const IosNotificationSettings(sound: true, alert: true, badge: true));
firebaseMessaging1.onIosSettingsRegistered
.listen((IosNotificationSettings setting) {
print('IOS Setting Registered');
});
firebaseMessaging1.getToken().then((token) {
print("token: "+token);
});
flutterLocalNotificationsPlugin1 = new FlutterLocalNotificationsPlugin();
var android = new AndroidInitializationSettings('#mipmap/ic_launcher');
var iOS = new IOSInitializationSettings();
var initSetttings = new InitializationSettings(android, iOS);
flutterLocalNotificationsPlugin1.initialize(initSetttings);
print(firebaseMessaging1.toString());
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
);
}
}
So the aim is simple. When the notification arrives depending on the activity we are in, it should perform different actions.
If in A, print notification arrived in A
If in B, print notification arrived in B
But the problem is, when I switch back to A from B (B was called from A using Navigator push), it still prints Notification arrived in B
Either the dispose doesn't dispose completely or I am missing something
dispose doesn't do anything fancy. It is your job to handle custom dispose behaviors.
More specifically, you have to explicitly clean all the mess you possibly made. In your situation, this translates into unsubscribing to firebase's stream.
This translates into the following:
StreamSubscription streamSubscription;
Stream myStream;
#override
void initState() {
super.initState();
streamSubscription = myStream.listen((foo) {
print(foo);
});
}
#override
void dispose() {
super.dispose();
streamSubscription.cancel();
}
You'll have to do the same thing for all listened streams and similar objects (such as Listenable)