kokogento
@kokogento (ここ げんと)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

画面遷移でFlutterError (Looking up a deactivated widget's ancestor is unsafe.が発生する

サインイン後に画面遷移させるとExceptionエラーが発生

「サインイン」というボタンを押したらFirebaseの匿名認証でサインインし、TOP画面に遷移したいです。

しかし、TOP画面へ遷移した直後下記のようなエラーが発生します。。

Exception has occurred.
FlutterError (Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.)

このエラーの意味が検索して調べてもいまいち理解できません。。。

デバッグの方法でも何でも構わないので、ほんの少しでも解決の糸口になるような事をご教授していただければ幸いです。

該当のソースコード

introduction_screen.dart

lib/screens/introduction/introduction_screen.dart
class IntroductionScreen extends StatelessWidget {

  void signInAnonymously(
      BuildContext context, UserProvider userProvider) async {
    userProvider.startLoading();
    String res = await AuthMethods().signInAnonymously();
    // if string returned is sucess, user has been created
    if (res == "success") {
      userProvider.endLoading();

      // .of(context)の部分でエラーが発生
      Navigator.of(context).pushReplacement(MaterialPageRoute(
        builder: (context) => const ResponsiveLayout(
          mobileScreenLayout: MobileScreenLayout(),
          webScreenLayout: WebScreenLayout(),
        ),
      ));
    } else {
      // show the error
      showSnackBar(context, res);
    }
  }

  @override
  Widget build(BuildContext context) {
    final userProvider = Provider.of<UserProvider>(context);
    return Scaffold(
      body: Center(
        child: Builder(
          builder: (context) {
            return ElevatedButton(
              child: !userProvider.getLoading
                  ? const Text('はじめる')
                  : const CircularProgressIndicator(color: primaryColor),
              onPressed: () => signInAnonymously(context, userProvider),
            );
          },
        ),
      ),
    );
  }
}

user_provider.dart

lib/providers/user_provider.dart
class UserProvider with ChangeNotifier {
  User? _user;
  final AuthMethods _authMethods = AuthMethods();
  bool _loading = false;

  User get getUser => _user!;

  bool get getLoading => _loading;

  void startLoading() {
    _loading = true;
    notifyListeners();
  }

  void endLoading() {
    _loading = false;
    notifyListeners();
  }

  Future<void> refreshUser() async {
    User user = await _authMethods.getUserDetails();
    _user = user;
    notifyListeners();
  }
}

responsive_layout.dart

lib/responsive/responsive_layout.dart
class ResponsiveLayout extends StatefulWidget {
  final Widget mobileScreenLayout;
  final Widget webScreenLayout;
  const ResponsiveLayout({
    Key? key,
    required this.mobileScreenLayout,
    required this.webScreenLayout,
  }) : super(key: key);

  @override
  State<ResponsiveLayout> createState() => _ResponsiveLayoutState();
}

class _ResponsiveLayoutState extends State<ResponsiveLayout> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(builder: (context, constraints) {
      if (constraints.maxWidth > webScreenSize) {
        // 600 can be changed to 900 if you want to display tablet screen with mobile screen layout
        return widget.webScreenLayout;
      }
      return widget.mobileScreenLayout;
    });
  }
}

main.dart

lib/main.dart
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();  
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider(
            create: (_) => UserProvider(),
          ),
        ],
        child: MaterialApp(
          title: 'LoveDan',
          home: StreamBuilder<User?>(
            stream: FirebaseAuth.instance.authStateChanges(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.active) {
                if (snapshot.hasError) {
                  return Center(
                    child: Text('${snapshot.error}'),
                  );
                } else if (snapshot.hasData) {
                  // User が null でなない、つまりサインイン済みのホーム画面へ
                  return const ResponsiveLayout(
                    mobileScreenLayout: MobileScreenLayout(),
                    webScreenLayout: WebScreenLayout(),
                  );
                } else {
                  // User が null である、つまり未サインインのサインイン画面へ
                  return IntroductionScreen();
                }
              }
              if (snapshot.connectionState == ConnectionState.waiting) {
                return const Center(
                  child: CircularProgressIndicator(),
                );
              }
              return IntroductionScreen();
            },
          ),
        ));
  }
}

環境

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^1.15.0
  cloud_firestore: ^3.1.3
  firebase_auth: ^3.3.16
  provider: ^6.0.2
 flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.5, on macOS 12.3.1 21E258 darwin-x64, locale en-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.2)
[✓] VS Code (version 1.71.2)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

• No issues found!

その他

全体のロジックは👇を参考にしてあります

👇のようにボタンをBuilderでラップしてみました。が、特に結果は変わらず・・・。

0

1Answer

introduction_screen.dartの👇のsignInAnonymouslyメソッド内の画面遷移処理を削除するとうまく行きました!!。

lib/screens/introduction/introduction_screen.dart
 Navigator.of(context).pushReplacement(MaterialPageRoute(
        builder: (context) => const ResponsiveLayout(
          mobileScreenLayout: MobileScreenLayout(),
          webScreenLayout: WebScreenLayout(),
        ),
      ));

main.dartでstreamでauthStateの変更を受け取っているので、ここで勝手に画面遷移していたものと思われます:sweat_smile:

lib/main.dart
stream: FirebaseAuth.instance.authStateChanges(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.active) {
                if (snapshot.hasError) {
                  return Center(
                    child: Text('${snapshot.error}'),
                  );
                } else if (snapshot.hasData) {
                  // User が null でなない、つまりサインイン済みのホーム画面へ
                  return const ResponsiveLayout(
                    mobileScreenLayout: MobileScreenLayout(),
                    webScreenLayout: WebScreenLayout(),
                  );
                } else {
                  // User が null である、つまり未サインインのサインイン画面へ
                  return IntroductionScreen();
                }
1Like

Your answer might help someone💌