이번에는 ChangeNotifierProvider를 통해 Provider를 구현해보자.
ChangeNotifier는 Flutter SDK에 포함된 클래스로 청취자에게 변경 알림을 제공해주는 것이다. 즉, ChangeNotifier를 통해 변화에 대해 구독할 수 있다.
Provider는 이전에 간단하게 알아보았으므로 구현하는 방법에 대해서 바로 알아보자.
라이브러리
아래 링크에 들어가 installing에 Provider 패키지 코드를 복사하여 pubspec.yaml 파일에 추가하여 다운로드한다.
dependencies:
provider: ^6.0.1
코드의 이해를 돕기 위해 폴더의 위치를 다음과 같이 구성한다.
폴더의 위치를 구성하고 Provider 패키지를 추가했다면 본격적으로 코드를 작성하도록 하자.
main.dart
import 'package:ev_app/src/provider/count_provider.dart';
import 'package:flutter/material.dart';
import 'package:ev_app/src/home.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ChangeNotifierProvider( // ChangeNotifierProvider를 통해 변화에 대해 구독(하나만 구독 가능)
create: (BuildContext context) => CountProvider(), // count_provider.dart
child: Home() // home.dart // child 하위에 모든 것들은 CountProvider에 접근 할 수 있다.
)
);
}
}
ChangeNotifierProvider를 통해 변화에 대해 구독한다.(하나만 구독 가능)
⇒ 여러 개를 구독하기 위해서는 MultProvider로 감싼 후 사용해야한다.
ChangeNotifierProvider를 통해 CountProvider()를 구독하는 것이고 CountProvider은 count_provider.dart에 생성된 것이다.
child 하위에 모든 것들은 CountProvider에 접근할 수 있고 Provider 선언한 위치에서 그 상위 Widget은 Provider에 접근할 수 없다.
home.dart
import 'package:ev_app/src/provider/count_provider.dart';
import 'package:flutter/material.dart';
import 'package:ev_app/src/ui/count_home_widget.dart';
import 'package:provider/provider.dart';
class Home extends StatelessWidget {
late CountProvider _countProvider;
@override
Widget build(BuildContext context) {
// Provider를 호출해 접근, listen: false를 통해 구독된 모든 위젯들에게 알림을 보내지 않게 한다.
_countProvider = Provider.of<CountProvider>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text("Provider Sample"),
),
body: CountHomeWidget(), // count_home_widget.dart
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
_countProvider.add(); // 클릭 되었을 때 add()
},),
IconButton(icon: Icon(Icons.remove),
onPressed: () {
_countProvider.remove(); // 클릭 되었을 때 remove()
},)
],),
);
}
}
Provider를 호출해 접근한다.
그 후 버튼을 눌렀을 때 더해지고 빼지는 연산을 구현한다.
count_home_widget.dart
import 'package:ev_app/src/provider/count_provider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CountHomeWidget extends StatelessWidget {
const CountHomeWidget({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Consumer<CountProvider>( // Consumer를 활용해서 provider에 접근하여 데이터를 받아올 수 있다
builder: (context, provider, child) {
return Text(
provider.count.toString(), // count를 화면에 출력
style: TextStyle(fontSize: 40.0),);
}
),
);
}
}
Consumer를 활용해서 provider에 접근하여 데이터를 받아올 수 있다.
return Center(
child: Text(
Provider.of<CounterProvider>(context).count.toString(),
),
);
Provide.of를 사용해서 CounterProvider로 직접 접근을 할 수 있으며 상태를 받아와 업데이트가 가능하다.
이렇게 위 코드로도 데이터를 받아올 수 있고 두 코드는 목적에 따라 활용해야 한다.
Provide.of를 사용하는 경우는 직접 접근해서 받아오는 경우로 현 위젯 전체가 리로드 되는 현상이 발생된다. 즉, 가벼운 위젯일 경우 바로 사용해도 무방하다.
Consumer를 사용하는 경우는 builder 부분만 호출되기 때문에 현 위젯이 리로드 되지 않는다. 즉, 여러 효과나 연산이 많이 있는 위젯일 경우는 Consumer를 사용하는 것이 좋을 것으로 보인다.
count_provider.dart
import 'package:flutter/material.dart';
// ChangeNotifier 상속 받이 상태 관리
// 이 안에 있는 맴버 변수 값들을 상태 관리 한다.
class CountProvider extends ChangeNotifier{
int _count = 0;
int get count => _count; // get 함수를 사용해 외부에서 접근이 가능하게 한다.
// 더하기
add(){
_count++;
notifyListeners(); // notifyListeners 호출해 업데이트된 값을 구독자에게 알림
}
// 빼기
remove(){
_count--;
notifyListeners(); // notifyListeners 호출해 업데이트된 값을 구독자에게 알림
}
}
Provider에서는 상태 관리를 직접 하지 않고 ChangeNotifier가 스스로 상태 관리를 한다.
get 함수를 통해 외부에서 _count를 접근 가능하게 한다.
다음으로 더하기, 빼기 함수가 있는데 여기서 notifyListeners를 사용하지 않으면 업데이트된 값을 구독자에게 알리지 못하므로 반드시 작성해야 한다.
위 코드를 모두 작성했다면 다음 영상과 같이 실행되는 것을 확인할 수 있다.
사용자는 Provider를 통해 데이터 클래스를 생성 요청하고, 그 데이터를 사용하는 뷰에서 구독만 해주면 데이터 변화를 자동으로 알림 받을 수 있게 된다. 모든 로직은 Provider가 관리하고 UI는 보여주기만 하면 된다.
참고
github
'Develop > Flutter' 카테고리의 다른 글
[Flutter - Error] INSTALL_FAILED_INSUFFICIENT_STORAGE (0) | 2021.12.24 |
---|---|
[Flutter - Error] Failed to start DevTools: Dart DevTools exited with code 255. (0) | 2021.12.22 |
[Flutter] 플러터 Bloc 패턴과 Provider (0) | 2021.12.21 |
[Flutter] 플러터 비동기 Future 와 Stream (0) | 2021.12.20 |
[Flutter] 플러터 FutureBuilder를 사용한 비동기 처리 (0) | 2021.11.16 |