Pushan Gupta
Pushan Gupta

Reputation: 3825

Dispose doesn't dispose completely

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

Upvotes: 1

Views: 2132

Answers (1)

R&#233;mi Rousselet
R&#233;mi Rousselet

Reputation: 276951

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)

Upvotes: 4

Related Questions