AutoDisposeStreamProvider is not being disposed at loggin out
Solution 1
In the documentation, the example is using a Stream
based on a StreamController
final messageProvider = StreamProvider.autoDispose<String>((ref) async* {
// Open the connection
final channel = IOWebSocketChannel.connect('ws://echo.websocket.org');
// Close the connection when the stream is destroyed
ref.onDispose(() => channel.sink.close());
// Parse the value received and emit a Message instance
await for (final value in channel.stream) {
yield value.toString();
}
});
In your case, your method is returning a Stream
. This changes the game rules. Just return the Stream
.
final AutoDisposeStreamProvider<List<fc_types.Room>> roomsListProvider =
StreamProvider.autoDispose<List<fc_types.Room>>(
(_) => FirebaseChatCore.instance.rooms(),
name: "List Rooms Provider",
);
Solution 2
Edit:
As you cannot cancel a Stream directly, you could just forward the FirebaseCore.instance.rooms()
and let the provider do the cleanup:
final AutoDisposeStreamProvider<List<fc_types.Room>> roomsListProvider =
StreamProvider.autoDispose<List<fc_types.Room>>(
(_) => FirebaseChatCore.instance.rooms(),
name: "List Rooms Provider",
);
Previous Answer:
autoDispose
only closes the provided Stream itself (the one you create by using async*
), but you will still need too close the Firebase stream yourself.
You can use onDispose()
as shown in the Riverpod documentation
ref.onDispose(() => rooms.close());
SalahAdDin
Soy Ingeniero de Sistemas y Computación Egresado de la Universidad de Colombia, emprendedor, aprendo muy fácilmente y me gusta hacerlo autónomamente. Me encanta trabajar en Sistemas Operativos Linux, muy buenos para trabajar en programación y afines, y jugar en Windows. Actualmente me desempeño autónomamente en desarrollo de aplicaciones web. Me gusta ayudar y aprender. I'm a Computer and Systems Engineer graduated from the National University of Colombia, entrepreneur, I learn easily and I like to do it autonomously. I love Working on Linux Operative Systems, they are very good for working in programming and allied, and i like playing in Windows. Currently in involved in autonomous web applications development. I like to help and to learn.
Updated on December 30, 2022Comments
-
SalahAdDin over 1 year
Currently, we are using Firebase to implement a simple chat on our application.
We handle the application's launch and authentication with Riverpod.
Launching goes like as follows:
@override Widget build(BuildContext context) { LocalNotificationService() .handleApplicationWasLaunchedFromNotification(_onSelectNotification); LocalNotificationService().setOnSelectNotification(_onSelectNotification); _configureDidReceiveLocalNotification(); // final navigator = useProvider(navigatorProvider); final Settings? appSettings = useProvider(settingsNotifierProvider); final bool darkTheme = appSettings?.darkTheme ?? false; final LauncherState launcherState = useProvider(launcherProvider); SystemChrome.setEnabledSystemUIOverlays( <SystemUiOverlay>[SystemUiOverlay.bottom], ); return MaterialApp( title: 'Thesis Cancer', theme: darkTheme ? ThemeData.dark() : ThemeData.light(), navigatorKey: _navigatorKey, debugShowCheckedModeBanner: false, home: Builder( builder: (BuildContext context) => launcherState.when( loading: () => SplashScreen(), needsProfile: () => LoginScreen(), profileLoaded: () => MainScreen(), ), ), ); }
Currently, we just enable logging out from main screen and rooms screen as follows:
ListTile( leading: const Icon(Icons.exit_to_app), title: const Text('Çıkış yap'), onTap: () => context.read(launcherProvider.notifier).signOut(), ),
Where
signOut
does:Future<void> signOut() async { tokenController.state = ''; userController.state = User.empty; await dataStore.removeUserProfile(); _auth.signOut(); state = const LauncherState.needsProfile(); }
The problem is, every time we goes to the
RoomsPage
and we do logout from it or from the main page (coming back from rooms), we get the same problem with firebase:The caller does not have permission to execute the specified operation.
. Of course,signout
closes the Firebase, thence Firebase throws this error; but, it is supposed after coming out from the RoomsScreen (it happens even when go back to the main screen), this widget is disposed therefore the connection should be closed, disposed, but it seems it is still on memory.The RoomPage screen is as follows:
class RoomsPage extends HookWidget { @override Widget build(BuildContext context) { final AsyncValue<List<fc_types.Room>> rooms = useProvider(roomsListProvider); return Scaffold( appBar: Header( pageTitle: "Uzmanlar", leading: const BackButton(), ), endDrawer: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 275), child: SideMenu(), ), body: rooms.when( data: (List<fc_types.Room> rooms) { if (rooms.isEmpty) { return Container( alignment: Alignment.center, margin: const EdgeInsets.only( bottom: 200, ), child: const Text('No rooms'), ); } return ListView.builder( itemCount: rooms.length, itemBuilder: ( BuildContext context, int index, ) { final fc_types.Room room = rooms[index]; return GestureDetector( onTap: () => pushToPage( context, ChatPage( room: room, ), ), child: Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), child: Row( children: <Widget>[ Container( height: 40, margin: const EdgeInsets.only( right: 16, ), width: 40, child: ClipRRect( borderRadius: const BorderRadius.all( Radius.circular(20), ), child: Image.network(room.imageUrl ?? ''), ), ), Text(room.name ?? 'Room'), ], ), ), ); }, ); }, loading: () => const Center( child: CircularProgressIndicator(), ), error: (Object error, StackTrace? stack) => ErrorScreen( message: error.toString(), actionLabel: 'Home', onPressed: () => Navigator.of(context).pop(), ), ), ); } }
And the provider is simple:
final AutoDisposeStreamProvider<List<fc_types.Room>> roomsListProvider = StreamProvider.autoDispose<List<fc_types.Room>>( (_) async* { final Stream<List<fc_types.Room>> rooms = FirebaseChatCore.instance.rooms(); await for (final List<fc_types.Room> value in rooms) { yield value; } }, name: "List Rooms Provider", );
I suppose the AutoDispose constructor makes this provider auto disposed when the widget is removed, so, it should close the connection with Firebase (as de documentation says).
WHat's the problem here?
What am i missing?
Should i open an issue about this?
-
SalahAdDin almost 3 yearsThe method 'close' isn't defined for the type 'Stream'.
-
SalahAdDin almost 3 yearsIt is suposed to be what i did, also i followed the documentation: pub.dev/documentation/riverpod/latest/riverpod/…
-
SalahAdDin almost 3 yearsAnd also, the types there are wrong:
final StreamProvider<List<fc_types.Room>> roomsProvider = StreamProvider<List<fc_types.Room>>( (_) => FirebaseChatCore.instance.rooms(), );