본문 바로가기

Flutter/07 State - Provider

[Flutter] Provider - errors(provider with Dialog)

오늘은 Provider 관련 에러들에 대해서 알아보겠습니다.

개발환경 : 윈도우11, 안드로이드 스튜디오(Arctic Fox 2020.3.1 Patch 4), flutter 2.10

소스코드 - https://github.com/mike-bskim/provider_overview

 

GitHub - mike-bskim/provider_overview

Contribute to mike-bskim/provider_overview development by creating an account on GitHub.

github.com

 

화면 랜더링과 동시에 다이얼로그 박스를 화면에 보여주려고 할때 나오는 에러입니다.

 

======== Exception caught by widgets library ========
The following assertion was thrown building Builder:
dependOnInheritedWidgetOfExactType<_LocalizationsScope>() or dependOnInheritedElement() 
was called before _HandleDialogPageState.initState() completed.

 

다이얼로그 박스는 위젯위에 보여주기 때문에 해당 위젯이 랜더링이 끝난후에 보여져야 한다.

이 문제는 "addPostFrameCallback" 을 사용하면 해결할 수 있다.

 

프로젝트 구성은 다음과 같다.

  • main.dart
  • ./models/counter.dart
  • ./pages/handle_dialog_page.dart

 

main.dart - 자세한 코드는 더보기 클릭

더보기
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'pages/counter_page.dart';
import 'pages/handle_dialog_page.dart';
import 'pages/navigate_page.dart';
import 'models/counter.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Counter>(
      create: (_) => Counter(),
      child: MaterialApp(
        title: 'addPostFrameCallback',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 30.0),
          child: ListView(
            shrinkWrap: true,
            children: [
              ElevatedButton(
                child: const Text(
                  'Counter Page',
                  style: TextStyle(fontSize: 20.0),
                ),
                onPressed: () => Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (_) => const CounterPage(),
                  ),
                ),
              ),
              const SizedBox(height: 20.0),
              ElevatedButton(
                child: const Text(
                  'Handle Dialog Page',
                  style: TextStyle(fontSize: 20.0),
                ),
                onPressed: () => Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (_) => const HandleDialogPage(),
                  ),
                ),
              ),
              const SizedBox(height: 20.0),
              ElevatedButton(
                child: const Text(
                  'Navigate Page',
                  style: TextStyle(fontSize: 20.0),
                ),
                onPressed: () => Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (_) => const NavigatePage(),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

 

counter.dart

 

import 'package:flutter/foundation.dart';

class Counter with ChangeNotifier {
  int counter = 0;

  void increment() {
    counter++;
    notifyListeners();
  }

  void update(int value) {
    counter = value;
    notifyListeners();
  }
}

 

handle_dialog_page.dart

"addPostFrameCallback" 부분을 주석처리하면 오류를 볼수 있다.

 

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../models/counter.dart';

class HandleDialogPage extends StatefulWidget {
  const HandleDialogPage({Key? key}) : super(key: key);

  @override
  _HandleDialogPageState createState() => _HandleDialogPageState();
}

class _HandleDialogPageState extends State<HandleDialogPage> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addPostFrameCallback((_) {
      showDialog(
        context: context,
        builder: (context) {
          return const AlertDialog(
            content: Text('Be careful!'),
          );
        },
      );
    });
  }

  @override
  Widget build(BuildContext context) {


    return Scaffold(
      appBar: AppBar(
        title: const Text('Handle Dialog'),
      ),
      body: Center(
        child: Text(
          '${context.watch<Counter>().counter}',
          style: const TextStyle(fontSize: 40.0),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () {
          context.read<Counter>().increment();
          if (context.read<Counter>().counter == 3) {
            WidgetsBinding.instance!.addPostFrameCallback((_) {
              showDialog(
                context: context,
                builder: (context) {
                  return const AlertDialog(
                    content: Text('Count is 3'),
                  );
                },
              );
            });
          }
        },
      ),
    );
  }
}