시리즈

Flutter provider 1

20191019
app state
flutter
provider
soc
state management

Flutter provider 1

이 글이 쓰인 시점에는 플러그인 메이저 버전이 3이었기 때문에 지금과 꽤 많은 차이가 생겼습니다. 
여기를 확인하세요.
 
provider package
provider cookbook
쉬운 한글 설명
StatelessWidget은 간편하게 쓰기에는 좋지만 SoC(Seperation of Concern) 측면에서 보면 약간 지저분해 보입니다. 딱 ui를 관리하는데 필요한 ephemeral state만 들어 있는게 보기에 좋습니다. 특히 app state를 콜백 함수를 이용해서 위젯 트리 안에서 끌어내리고 올리고 하기 시작하면 스파게티가 되기 쉽습니다.
참고 : google io’19 provider
그렇다고 글로벌하게 state를 사용하자니 OOP의 장점들이 사라지고 성능까지 저하됩니다.
provider에서는 app state를 프레임워크에서 관리하게 만듭니다. 데이터가 필요한 위젯에서만 데이터를 사용하게 해줍니다.

알아야 할 것들

데이터 접근만 필요한 경우 (UI 갱신 X)


데이터의 변화가 있고, 데이터의 변화를 UI에 반영해서 갱신해야 하는 경우


그 외의 것들


1. Provider / Provider.of

Provider<type> : 데이터를 제공하는 쪽, (공식 문서에는 expose를 사용했다.) Provider.of<type> : 데이터를 받는 쪽
여기서 type은 주고 받을 데이터의 타입을 말합니다.
값 하나를 전달 할 때는 Provider<>.value 위젯을 사용합니다.

Provider


String data = "top secret";

Provider<String>.value(
  value: data,
  child: MaterialApp(
    home: Home(),
  )
)
복잡한 위젯을 전달할 때도 유용합니다. 여기서 builder에 전달된 생성자는 위젯 트리에 삽입될 때 단 한 번만 호출됩니다.
Provider<MyComplexClass>(
  builder: (context) => MyComplexClass(),
  dispose: (context, value) => value.dispose()
  child: SomeWidget(),
)
이렇게 Provider로 지정하면 위젯 트리 상에서 Provider의 자손 위젯 들은 이 값을 확인할 수 있습니다.

Provider.of

간단하게 값을 읽을 때는 Provider.of 를 사용합니다. Provider.of<type> 이 호출되면 이 위젯에서부터 위젯 트리를 따라 올라가면서 같은 타입의 Provider를 찾습니다.

예제 1

아래 예제를 보면 MyApp에 있는 Provider 위젯에서 data를 제공하고 Level2에 있는 Text에서 데이터에 접근하고 있다.





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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final String data = '123123625'; // 위젯 간 주고 받을 데이터

  @override
  Widget build(BuildContext context) {
    return Provider<String>( // Provider, 또는 Provider<>.value를 사용해도 됨
      builder: (context) => data, // builder 속성으로 줄 데이터 지정
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            title: Text(data),
          ),
          body: Level1(), // go down
        ),
      ),
    );
  }
}

class Level1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Level2(), // go down
    );
  }
}

class Level2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(Provider.of<String>(context)), // 여기서 데이터를 사용 Provider.of
    );
  }
}


2. ChangeNotifier / ChangeNotifierProvider / Consumer

ChangeNotifier

ChangeNotifier 위젯은 Provider 패키지가 아니고 flutter:foundation 에 들어있기 때문에 별도의 import나 package get 이 필요없다.
어떤 데이터가 extends ChangeNotifier (또는 mixin ChangeNotifier) 가 달리면 다른 리스너들이 이 데이터를 구독하고 있다가 변화가 있으면 알림을 받을 수 있게 된다.
ChangeNotifier is optimized for small numbers (one or two) of listeners. It is O(N) for adding and removing listeners and O(N²) for dispatching notifications (where N is the number of listeners).
doc에서는 리스너를 많이 두지는 말라고 충고한다.
Provider에서 사용할 때는 모델 클래스에 걸어둔다.

ChangeNotifierProvider

CNP는 provider 패키지가 필요합니다.
ChangeNotifierProvider는 ChangeNotifier를 제공(또는 expose)하는 위젯이다.
약간 스마트한 Provider<ChangeNotifier> 라고 보면 된다.
void main() {
  runApp(
    ChangeNotifierProvider(
      builder: (context) => CartModel(),
      child: MyApp(),
    ),
  );
}
CartModel 인스턴스가 필요없어지면 자동으로 dispose 하게 된다.

Consumer

CartModel이 CNP에 의해서 노출된 상태에서 Consumer를 사용할 수 있다. Consumer 위젯을 사용하기 위해서 필요한 유일한 속성은 builder 콜백이다.
이 콜백함수는 CN에서 notifyListener가 사용될 때 마다 호출되어서 Consumer 의 자손 위젯들의 build함수를 전부 호출한다.
매개변수를 3개 가지는데, 첫 번째는 context이고 두 번째는 CN의 인스턴스다. 세 번째 child는 최적화를 위한 옵션이다.
Foo(
  child: Consumer<A>(
    builder: (_, a, child) {
      return Bar(a: a, child: child);
    },
    child: Baz(),
  ),
)
위 예제에서 notifyListener() 가 호출되면 Bar 위젯만 다시 빌드된다.

Provider.of 2

결국 CNP도 Provider이기 때문에 Provider.of 로 CN 데이터를 받을 수도 있다. CN 에서 notifyListener() 메소드를 통해서 리스너들에게 알림을 보내면 Provider.of 에서도 받게 된다. 이걸 받을 지 말지를 결정하기 위해서 Provider.of<> 에는 listen 이라는 속성이 있다. 기본 값은 true이고, 이걸 false로 하면 notifyListeners의 영향을 받지 않는다.
결정적인 Consumer와의 차이는 build 함수가 없기 때문에 UI 갱신에 어려움이 있다. 그러니 UI를 갱신할 필요가 없고 데이터를 읽기(사용)만 할 때 Provider.of를 사용해도 좋다.

예제 2

TaskData CN에서 notifyListener가 호출되면 builder 콜백이 실행된다.





코드 보기
class TaskList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<TaskData>(
      builder: (context, taskData, child) {
        return ListView.builder(
          itemBuilder: (context, index) {
            return TaskTile(
                taskTitle: taskData.tasks[index].name,
                isChecked: taskData.tasks[index].isDone,
          },
          itemCount: taskData.taskCount,
        );
      },
    );
  }
}

.

piano (press key Q)

Categories

flutter ( 82 ) dart ( 34 ) android ( 32 ) kotlin ( 11 ) plugin ( 8 ) provider ( 8 ) vim ( 7 ) bloc ( 6 ) iOS ( 6 ) state management ( 6 ) 플러터 ( 6 ) PS ( 5 ) algorithm ( 5 ) architecture ( 5 ) async ( 5 ) getx ( 5 ) java ( 5 ) API ( 4 ) BOJ ( 4 ) class ( 4 ) daily ( 4 ) git ( 4 ) golang ( 4 ) memo ( 4 ) riverpod ( 4 ) state ( 4 ) stream ( 4 ) test ( 4 ) web ( 4 ) widget ( 4 ) windows ( 4 ) HTTP ( 3 ) androidX ( 3 ) app state ( 3 ) context ( 3 ) crash ( 3 ) db ( 3 ) editor ( 3 ) error ( 3 ) extension ( 3 ) github ( 3 ) hive ( 3 ) ide ( 3 ) package ( 3 ) pubspec ( 3 ) python ( 3 ) syntax ( 3 ) vscode ( 3 ) app icon ( 2 ) await ( 2 ) chocolatey ( 2 ) consumer ( 2 ) cp949 ( 2 ) deployment ( 2 ) dev ( 2 ) flavor ( 2 ) gesture ( 2 ) globalkey ( 2 ) go ( 2 ) google ( 2 ) hack ( 2 ) js ( 2 ) json ( 2 ) key ( 2 ) keystore ( 2 ) list ( 2 ) listview ( 2 ) lock ( 2 ) mac ( 2 ) map ( 2 ) navigation ( 2 ) nosql ( 2 ) project ( 2 ) pub ( 2 ) recyclerview ( 2 ) rxdart ( 2 ) sdk ( 2 ) selector ( 2 ) setting ( 2 ) size ( 2 ) soc ( 2 ) synchronized ( 2 ) tdd ( 2 ) tip ( 2 ) version ( 2 ) viewmodel ( 2 ) vundle ( 2 ) webview ( 2 ) xcode ( 2 ) yaml ( 2 ) ( 2 ) 플러터 단점 ( 2 ) 16.0 ( 1 ) 2.0 ( 1 ) 2023 ( 1 ) AATP2 ( 1 ) ChangeNotifierProvider ( 1 ) Example ( 1 ) Guava ( 1 ) ImageReader ( 1 ) Mo's algorithm ( 1 ) OAuth2 ( 1 ) OpenGL ( 1 ) Oreo ( 1 ) ProgressBar ( 1 ) REST API ( 1 ) Trie ( 1 ) activity ( 1 ) adaptive ( 1 ) android P ( 1 ) android context ( 1 ) android11 ( 1 ) apktool2 ( 1 ) app exit ( 1 ) append ( 1 ) appicon ( 1 ) arkit ( 1 ) array ( 1 ) asciidoc ( 1 ) async * ( 1 ) async* ( 1 ) audio ( 1 ) authorization ( 1 ) await for ( 1 ) behaviorsubject ( 1 ) beta ( 1 ) binary ( 1 ) binarysearch ( 1 ) blender ( 1 ) book ( 1 ) bottomsheet ( 1 ) break ( 1 ) broadcast ( 1 ) browser ( 1 ) bubbles ( 1 ) bug ( 1 ) build ( 1 ) buildcontext ( 1 ) buildnumber ( 1 ) bundle ( 1 ) button ( 1 ) bytecode ( 1 ) cache ( 1 ) camera2 ( 1 ) cameramanager ( 1 ) cd ( 1 ) chrome ( 1 ) ci ( 1 ) circle ( 1 ) clean ( 1 ) clean architecture ( 1 ) cli ( 1 ) clip ( 1 ) clipboard ( 1 ) cloud ide ( 1 ) cmdlet ( 1 ) code ( 1 ) coding test ( 1 ) command ( 1 ) comparator ( 1 ) complexity ( 1 ) concurrency ( 1 ) conditional ( 1 ) const ( 1 ) constraint ( 1 ) constraintlayout ( 1 ) controlc ( 1 ) controlv ( 1 ) converter ( 1 ) copy ( 1 ) copy project ( 1 ) coupling ( 1 ) coverage ( 1 ) cp ( 1 ) css ( 1 ) cupertino ( 1 ) cursor ( 1 ) cv ( 1 ) data class ( 1 ) data structure ( 1 ) dataBinding ( 1 ) database ( 1 ) debounce ( 1 ) decompile ( 1 ) delegate ( 1 ) deno ( 1 ) design pattern ( 1 ) development ( 1 ) device ( 1 ) di ( 1 ) dialog ( 1 ) dio ( 1 ) drawable ( 1 ) drug ( 1 ) emmet ( 1 ) encoding ( 1 ) english ( 1 ) entries ( 1 ) environment ( 1 ) equality ( 1 ) equatable ( 1 ) euc-kr ( 1 ) euckr ( 1 ) exit ( 1 ) expand ( 1 ) expanded ( 1 ) export ( 1 ) extension method ( 1 ) facade ( 1 ) fake ( 1 ) field ( 1 ) figma ( 1 ) final ( 1 ) fixed ( 1 ) flutter pub ( 1 ) flutter web ( 1 ) flutter_inappwebview ( 1 ) flutter_test ( 1 ) flutterflow ( 1 ) fold ( 1 ) fonts ( 1 ) form ( 1 ) frame ( 1 ) future ( 1 ) gestureDetector ( 1 ) gestureRecognizer ( 1 ) gesturearena ( 1 ) get-command ( 1 ) get_cli ( 1 ) getbuilder ( 1 ) getx단점 ( 1 ) gitignore ( 1 ) glut ( 1 ) google fonts ( 1 ) gopath ( 1 ) goto ( 1 ) gradient ( 1 ) graphics ( 1 ) gvim ( 1 ) hackaton ( 1 ) hash ( 1 ) hashmap ( 1 ) hot reload ( 1 ) how to ( 1 ) html ( 1 ) i18n ( 1 ) icon ( 1 ) id ( 1 ) impeller ( 1 ) implementation ( 1 ) import ( 1 ) indicator ( 1 ) inkwell ( 1 ) interrupt ( 1 ) intl ( 1 ) introduction ( 1 ) io ( 1 ) isar ( 1 ) iterable ( 1 ) iteration ( 1 ) javascript ( 1 ) julia ( 1 ) juno ( 1 ) jupyter ( 1 ) kakaomap ( 1 ) keytool ( 1 ) korean ( 1 ) kotlin syntax ( 1 ) l10n ( 1 ) lambda ( 1 ) language ( 1 ) layer ( 1 ) layout ( 1 ) lineageOS ( 1 ) localkey ( 1 ) localtoglobal ( 1 ) long list ( 1 ) ls ( 1 ) mac osx ( 1 ) markdown ( 1 ) markup ( 1 ) material ( 1 ) method ( 1 ) microtask ( 1 ) migrate ( 1 ) mintlify ( 1 ) mock ( 1 ) module ( 1 ) monitor ( 1 ) moor ( 1 ) mouse ( 1 ) mouseregion ( 1 ) multiplatform ( 1 ) multiset ( 1 ) multithread ( 1 ) mutable ( 1 ) mvvm ( 1 ) new ( 1 ) node ( 1 ) nodejs ( 1 ) nosuchmethod ( 1 ) null-safety ( 1 ) numberformat ( 1 ) nvim ( 1 ) object ( 1 ) objectbox ( 1 ) objectkey ( 1 ) obx ( 1 ) online ide ( 1 ) operator ( 1 ) orientation ( 1 ) parabeac ( 1 ) parse ( 1 ) paste ( 1 ) path ( 1 ) pattern ( 1 ) pitfall ( 1 ) play store ( 1 ) pod ( 1 ) podfile ( 1 ) pointer ( 1 ) pointers ( 1 ) powershell ( 1 ) private ( 1 ) programming ( 1 ) pull to refresh ( 1 ) puzzle ( 1 ) pycharm ( 1 ) realitykit ( 1 ) recursion ( 1 ) reduce ( 1 ) reference ( 1 ) regex ( 1 ) regular expression ( 1 ) release note ( 1 ) renderbox ( 1 ) renderobject ( 1 ) repl ( 1 ) repository ( 1 ) response ( 1 ) rm ( 1 ) rotue ( 1 ) round ( 1 ) run ( 1 ) scope ( 1 ) scroll ( 1 ) search ( 1 ) server ( 1 ) serverless ( 1 ) service ( 1 ) sharp ( 1 ) singlerepo ( 1 ) singleton ( 1 ) sketch ( 1 ) sliver ( 1 ) sliverlist ( 1 ) snippets ( 1 ) sogae ( 1 ) sorting ( 1 ) source ( 1 ) sparse ( 1 ) sparse array ( 1 ) spec ( 1 ) split ( 1 ) sqflite ( 1 ) sqlite ( 1 ) sqrt decomposition ( 1 ) stateful ( 1 ) statefulwidget ( 1 ) step ( 1 ) stepper ( 1 ) string ( 1 ) stringbuffer ( 1 ) stringbuilder ( 1 ) studio ( 1 ) study ( 1 ) sub-directory ( 1 ) svn ( 1 ) swiftui ( 1 ) swipe to refresh ( 1 ) system_alert_window ( 1 ) system_cache ( 1 ) systemnavigator ( 1 ) tail recursion ( 1 ) tailrec ( 1 ) tap test ( 1 ) text ( 1 ) texteditingcontroller ( 1 ) textfield ( 1 ) texttheme ( 1 ) themedata ( 1 ) then ( 1 ) thread ( 1 ) throttle ( 1 ) time ( 1 ) tool ( 1 ) tools ( 1 ) tooltip ( 1 ) ts ( 1 ) tutorial ( 1 ) typescript ( 1 ) ui ( 1 ) unittest ( 1 ) update ( 1 ) usb ( 1 ) utf8 ( 1 ) ux ( 1 ) valuekey ( 1 ) variable ( 1 ) vector ( 1 ) versioncode ( 1 ) very_good ( 1 ) view ( 1 ) vim plugin ( 1 ) vimrc ( 1 ) virtualenv ( 1 ) wasm ( 1 ) web app ( 1 ) webview_flutter ( 1 ) while ( 1 ) widget tree ( 1 ) window ( 1 ) wsl ( 1 ) yield ( 1 ) 강의 ( 1 ) 개발 ( 1 ) 개발 공부 ( 1 ) 공부법 ( 1 ) 그래픽스 ( 1 ) 꼬리재귀 ( 1 ) 꿀팁 ( 1 ) 데노 ( 1 ) 두줄 ( 1 ) 디노 ( 1 ) 번역 ( 1 ) 블록 ( 1 ) 상태관리 ( 1 ) 실험 ( 1 ) 안드로이드 ( 1 ) 안드로이드프로젝트 ( 1 ) 안드로이드프로젝트복사 ( 1 ) 어이없는 ( 1 ) 조건부 임포트 ( 1 ) 주절주절분노조절실패의식으흐름 ( 1 ) 패키지 ( 1 ) 프로젝트복사 ( 1 ) 플러그인 ( 1 )