Harshvardhan R
Harshvardhan R

Reputation: 477

How to dispose stream on closing flutter app?

I have a stream in my flutter app that is continuosly detecting the network change .It is defined in the main function.

Map _source = {ConnectivityResult.none: false};
CurrentConnectivity _connectivity = CurrentConnectivity.instance;
void main() async{
  WidgetsFlutterBinding.ensureInitialized();

  await init();
  HttpOverrides.global = new MyHttpOverrides();


  _connectivity.initialise();
  _connectivity.myStream.listen((source) {
    _source=source;
  }, onError: (err) {
    print(err);
  }, cancelOnError: false);

  runApp(AppWidget());
  _connectivity.disposeStream();
}

But when i navigate i get this exception

EXCEPTION

E/flutter ( 6822): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Bad state: Cannot add new events after calling close
E/flutter ( 6822): #0      _BroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:251:24)
E/flutter ( 6822): #1      _StreamSinkWrapper.add (dart:async/stream_controller.dart:873:13)
E/flutter ( 6822): #2      CurrentConnectivity._checkStatus (package:iris_flutter/core/network/current_connectivity.dart:61:21)
E/flutter ( 6822): #3      _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter ( 6822): #4      _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter ( 6822): #5      _FutureListener.handleValue (dart:async/future_impl.dart:141:18)
E/flutter ( 6822): #6      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
E/flutter ( 6822): #7      Future._propagateToListeners (dart:async/future_impl.dart:711:32)
E/flutter ( 6822): #8      Future._completeWithValue (dart:async/future_impl.dart:526:5)
E/flutter ( 6822): #9      _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:36:15)
E/flutter ( 6822): #10     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:298:13)
E/flutter ( 6822): #11     SendOfflineRequests.call (package:iris_flutter/features/faculty/attendance/domain/usecases/offline_requests/send_offline_requests.dart)
E/flutter ( 6822): #12     _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter ( 6822): #13     _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter ( 6822): #14     _FutureListener.handleValue (dart:async/future_impl.dart:141:18)
E/flutter ( 6822): #15     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
E/flutter ( 6822): #16     Future._propagateToListeners (dart:async/future_impl.dart:711:32)
E/flutter ( 6822): #17     Future._completeWithValue (dart:async/future_impl.dart:526:5)
E/flutter ( 6822): #18     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:36:15)
E/flutter ( 6822): #19     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:298:13)
E/flutter ( 6822): #20     OfflineClassesRepositoryImpl.sendOfflineRequests (package:iris_flutter/features/faculty/attendance/data/repositories/offline_requests_repository_impl.dart)
E/flutter ( 6822): #21     _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter ( 6822): #22     _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter ( 6822): #23     _FutureListener.handleValue (dart:async/future_impl.dart:141:18)
E/flutter ( 6822): #24     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
E/flutter ( 6822): #25     Future._propagateToListeners (dart:async/future_impl.dart:711:32)
E/flutter ( 6822): #26     Future._completeWithValue (dart:async/future_impl.dart:526:5)
E/flutter ( 6822): #27     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:36:15)
E/flutter ( 6822): #28     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:298:13)
E/flutter ( 6822): #29     StudentDetailsFacultyLocalDataSourceImpl.deleteAllMarkedRecords (package:iris_flutter/features/faculty/attendance/data/datasources/students/student_details_faculty_local_data_source.dart)
E/flutter ( 6822): #30     _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter ( 6822): #31     _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter ( 6822): #32     _FutureListener.handleValue (dart:async/future_impl.dart:141:18)
E/flutter ( 6822): #33     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
E/flutter ( 6822): #34     Future._propagateToListeners (dart:async/future_impl.dart:711:32)
E/flutter ( 6822): #35     Future._completeWithValue (dart:async/future_impl.dart:526:5)
E/flutter ( 6822): #36     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:36:15)
E/flutter ( 6822): #37     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:298:13)
E/flutter ( 6822): #38     LocalStorage.deleteAllStoredMarkings (package:iris_flutter/core/util/local_storage.dart)
E/flutter ( 6822): #39     _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter ( 6822): #40     _CustomZone.runUnary (dart:async/zone.dart:1085:19)
E/flutter ( 6822): #41     _FutureListener.handleValue (dart:async/future_impl.dart:141:18)
E/flutter ( 6822): #42     Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:682:45)
E/flutter ( 6822): #43     Future._propagateToListeners (dart:async/future_impl.dart:711:32)
E/flutter ( 6822): #44     Future._completeWithValue (dart:async/future_impl.dart:526:5)
E/flutter ( 6822): #45     _AsyncAwaitCompleter.complete (dart:async-patch/async_patch.dart:36:15)
E/flutter ( 6822): #46     _completeOnAsyncReturn (dart:async-patch/async_patch.dart:298:13)
E/flutter ( 6822): #47     DeleteStatement.go.<anonymous closure> (package:moor/src/runtime/query_builder/statements/delete.dart)
E/flutter ( 6822): #48     _rootRunUnary (dart:async/zone.dart:1192:38)
E/flutter ( 6822): #49     _
I/Toast   ( 6822): Show toast from OpPackageName:com.example.iris_flutter, PackageName:com.example.iris_flutter

It works if i do not dispose the stream but i have heard that it is not a good practice to leave the stream open. Is there a better way to close the stream or is closing the stream necessary.

EDIT1 For some answers that say that i need to use WidgetsBindingObserver i want to point out that i need to initialise the stream in main ,else the connectivity change is detected multiple times if i initialise it in a stateful/stateless widget, which breaks some logic in the code i have written.

class LifeCycle extends StatefulWidget {
  @override
  _LifeCycleState createState() => _LifeCycleState();
}
class _LifeCycleState extends State<LifeCycle> with WidgetsBindingObserver {

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }
  
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print(state);
    if(state==AppLifecycleState.paused){
      GlobalClassThatInitialisesStream.disposeConnectivityStream();
    }
    if(state==AppLifecycleState.resumed){
      GlobalClassThatInitialisesStream.initialiseConnectivityStream();
    }
  }

  @override
  Widget build(BuildContext context) {
    return AppWidget();
  }
}

Upvotes: 2

Views: 15539

Answers (2)

Alok
Alok

Reputation: 8978

See if you are really looking for a disposing your stream in flutter. The best way to do it using via Flutter dispose.

To give you a jist about what inbuilt dispose() method does is, when your State is not active or finishes, it destroys your ChangeNotifiers/Controllers/Streams etc, and prevents your State to rebuild again, hence you don't see that error/warning

So, just make sure you have that in your StatefulWidget()

@override
void dispose() {
  // you dispose your stream here
  // or check if that works out _connectivity.dispose();
  _connectivity.disposeStream();
  super.dispose();
}

Hope that helps :)

Upvotes: 1

Moiz Sohail
Moiz Sohail

Reputation: 648

I dont really get the exact question your trying to ask.

A. IF you want to close the stream on app exit You can just call stream.cancel() when the app exits. How to detect when the app exits? For that you can make use of life cycle in flutter. Check the following youtube tutorial to learn more about it.

https://youtu.be/D_IWy2BXnEI

B.IF you are trying to fix the exception that is being raised due to navigation Create a separate global class that checks for network connectivity. And initialize the stream inside rather than in the main function. This way when you navigate out of the main you will not see this exception.

Upvotes: 3

Related Questions