rrousselGit / provider

InheritedWidgets, but simple
https://pub.dev/packages/provider
MIT License
5.12k stars 512 forks source link

Provider doesn't get rid of ViewModel after disposing of the View - ^6.0.1 #697

Closed Berthelmaster closed 3 years ago

Berthelmaster commented 3 years ago

Describe the bug When clicking back on emulators, and the view is disposed, the state of the viewmodel is maintained. This means that the next time the view is opened, it is loaded with state from an old view, which is not intended in my app at least.

To Reproduce

main.dart

`void main() { runApp(const MyApp()); }

class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key);

@override Widget build(BuildContext context) { return MultiProvider(providers: [ ChangeNotifierProvider( create: () => CreateRoomViewModel(), ), ChangeNotifierProvider( create: () => RoomSelectionViewModel(), ), ChangeNotifierProvider( create: (context) => RoomInstanceViewModel(), ) ], child: MaterialApp( theme: ThemeData( primarySwatch: Colors.blue ), initialRoute: '/', routes: { / List of routes and what they do / // Find or Create Room '/': (context) => const Main(), // Shows the room and valid courts '/room': (context) => RoomInstance.optional(), // Create a room '/create': (context) => const CreateRoom() }, )); } }`

View Model

`import 'dart:io'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:racket_match/services/hub_clients/on_connection_join.dart'; import 'package:racket_match/services/room_service.dart'; import 'package:racket_match/models/match.dart';

class RoomInstanceViewModel with ChangeNotifier {

bool _loading = false; String? _roomId; List _matches = []; var _onConnectionJoinHub;

RoomInstanceViewModel(){ print('CAAALEED'); _loading = false; _roomId = null; _matches = []; }

bool get isLoading => _loading; List get matches => _matches;

void updateMatch(Match match){ _matches.add(match); print(_matches.length); notifyListeners(); }

void setupHubConnection(String roomId) async { print("Matches: ${_matches.length}"); print("Loading?: $_loading"); _loading = true; _onConnectionJoinHub = await OnConnectionJoin(roomId, onNewConnection).initialize(); notifyListeners(); }

void onNewConnection(List? object){ var aa = object.toString(); print('New Connection!! $aa'); }

void switchLoading() => _loading = !_loading;

Future selectRoomByRoomID(String roomID) async { print(roomID); var request = await RoomService.getRoomFromIdentifier(roomID);

if(request.statusCode == 200){
  return request.body;
}

throw Exception("Could not find room");

}

void clearViewModel(){ _loading = false; _roomId = null; _matches = []; }

}`

View

`import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:racket_match/Widgets/match_graphic.dart'; import 'package:racket_match/models/match.dart'; import 'package:racket_match/models/player.dart'; import 'package:racket_match/models/room.dart'; import 'package:racket_match/services/hub_clients/on_connection_join.dart'; import 'package:racket_match/view_models/room_instance_view_model.dart'; import 'package:racket_match/widgets/match_graphic_list.dart';

//ignore: must_be_immutable class RoomInstance extends StatefulWidget{ RoomInstance.optional({Key? key}) : super(key: key); RoomInstance({Key? key, required this.room}) : super(key: key);

late Room room;

@override State createState() => _RoomInstanceState(); }

class _RoomInstanceState extends State with WidgetsBindingObserver{ bool hubActive = false; late RoomInstanceViewModel roomInstanceViewModel;

@override void dispose() { print('Disposed'); // This should really be fixed!? roomInstanceViewModel.clearViewModel(); super.dispose(); }

@override Widget build(BuildContext context) { var we = MediaQuery.of(context).size.width; var he = MediaQuery.of(context).size.height;

Player player1 = Player(id: 1, name: 'Jens Stage Stage', team: Team.team1);
Player player2 = Player(id: 2, name: 'PLayer_2', team: Team.team1);
Player player3 = Player(id: 3, name: 'PLayer_3', team: Team.team2);
Player player4 = Player(id: 4, name: 'PLayer_4', team: Team.team2);
Player player5 = Player(id: 5, name: 'PLayer_5', team: Team.team1);
Player player6 = Player(id: 6, name: 'PLayer_6', team: Team.team2);

Match match1 = Match(id: 1, players: [player1, player2, player3, player4]);
Match match2 = Match(id: 2, players: [player5, player6]);
var matches = [match1, match2];

roomInstanceViewModel = Provider.of<RoomInstanceViewModel>(context);
if(!hubActive) {
  hubActive = true;
  roomInstanceViewModel.setupHubConnection(widget.room.uniqueRoomIdentifier.toString());
}

// title: Text(widget.room.roomName),
return Scaffold(
  backgroundColor: const Color(0xFF1F1A30),
  body: Container(
    margin: const EdgeInsets.only(left: 10.0, right: 10.0),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        SizedBox(
          height: he * 0.04,
        ),
        Center(
          child: Text('Room ID: ${widget.room.uniqueRoomIdentifier.toString()}',
            style: GoogleFonts.heebo(
              color:  const Color(0xFF9746A0).withOpacity(0.9),
              fontWeight: FontWeight.bold,
              letterSpacing: 0.5,)),
        ),
        MatchGraphicList(matches: roomInstanceViewModel.matches),
        ElevatedButton(
          onPressed: (){
            roomInstanceViewModel.updateMatch(match1);
          },
          child: const Text('123'),
        )
      ],
    ),
  )

);

} }`

Expected behavior The View Model should be cleared when exiting a given view, getting it through Provider.of(context);

Is this normal behaviour, is this supposed to happen?

732504350 commented 2 years ago

@Berthelmaster Hi, there. I have the same issue about quit the page but the viewmodel didn't dispose. Could you please tell me how to solve it?

Berthelmaster commented 2 years ago

Hi! I switched package. Wasn't able to resolve

732504350 commented 2 years ago

Thank you for reply~