
Provider๊ฐ ์ ๊ณตํ๋ ์ํ๋ฅผ โ๊ตฌ๋
(consume)โํด์ UI๋ก ๊ทธ๋ฆฌ๋ ์์ ฏ
Provider โ UI๋ฅผ ์ฐ๊ฒฐํ๋ ์ ์ ์ญํ ์ ํ๋ ์์ ฏ
์ผ๋ฐ StatelessWidget / StatefulWidget
Provider ์ํ๋ฅผ ์ง์ ๊ฐ์งํ ์ ์์
์ํ ๋ณ๊ฒฝ ์ ์๋ ๋ฆฌ๋น๋ โ
๊ทธ๋์ Riverpod๊ฐ ์ ๊ณตํ๋ Consumer ๊ณ์ด ์์ ฏ์ด ํ์ํ ๊ฒ
StatelessWidget + Consumer ํฉ์ณ์ง ํํ
๊ฐ์ฅ ๋ง์ด ์ฐ๋ ๊ธฐ๋ณธํ
class MyWidget extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final state = ref.watch(counterProvider);
return Text('$state');
}
}
์ํ ๊ตฌ๋
๊ฐ๋ฅ (ref.watch)
๋ด๋ถ์ State ์์
์ฝ๋ ์งง๊ณ ๊ฐ๋
์ฑ ์ข์
UI๊ฐ ์ธ๋ถ ์ํ(provider) ์๋ง ์์กดํ ๋
๋ฒํผ ํด๋ฆญ, ์์ด์ฝ ํ ๊ธ, ๋ฆฌ์คํธ ์์ดํ
๋ฑ
โ
๋จ์, ๊น๋
โ initState, dispose ์ฌ์ฉ ๋ถ๊ฐ
์ผ๋ฐ ์์ ฏ ์์์ ์ผ๋ถ๋ง ์ํ ๊ตฌ๋
ํ ๋ ์ฌ์ฉ
๋น๋ ๋ฒ์๋ฅผ ์ต์ํํ๋ ์ฉ๋
class MyWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
Text('๊ณ ์ UI'),
Consumer(
builder: (context, ref, child) {
final state = ref.watch(counterProvider);
return Text('$state');
},
),
],
);
}
}
๋ถ๋ชจ๋ StatelessWidget ์ ์ง
Consumer ๋ด๋ถ๋ง ๋ฆฌ๋น๋
UI ์ผ๋ถ๋ง ์ํ์ ๋ฐ์ํด์ผ ํ ๋
์ฑ๋ฅ ์ต์ ํ ํ์ํ ๋
โ
๋ถํ์ํ ๋ฆฌ๋น๋ ๋ฐฉ์ง
โ ์ฝ๋๊ฐ ์ค์ฒฉ๋๋ฉด ๊ฐ๋
์ฑ ๋จ์ด์ง
StatefulWidget + Consumer
๋ผ์ดํ์ฌ์ดํด + provider ๋ ๋ค ํ์ํ ๋
class MyWidget extends ConsumerStatefulWidget {
ConsumerState<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends ConsumerState<MyWidget> {
void initState() {
super.initState();
ref.read(counterProvider.notifier).init();
}
Widget build(BuildContext context) {
final state = ref.watch(counterProvider);
return Text('$state');
}
}
initState, dispose ์ฌ์ฉ ๊ฐ๋ฅ
ref๋ฅผ State ์์์ ์ง์ ์ฌ์ฉ
ํ๋ฉด ์ง์
์ API ํธ์ถ
AnimationController
ScrollController
Timer, Stream ๊ด๋ฆฌ
โ
์ ์ด๋ ฅ ์ต๊ณ
โ ๊ตฌ์กฐ๊ฐ ๊ฐ์ฅ ๋ฌด๊ฑฐ์
Open-Meteo๋ ๋ฌด๋ฃ(๋น์์ ์ )๋ก ์ ์ธ๊ณ ๋ ์จ ๋ฐ์ดํฐ๋ฅผ JSON์ผ๋ก ์ ๊ณตํ๋ REST API
| API ์ด๋ฆ | ์ค๋ช |
|---|---|
| Weather Forecast API | ์ค์๊ฐ + ์๋ณด(์ต๋ 16์ผ) ๋ ์จ ๋ฐ์ดํฐ (Open Meteo) |
| Historical Weather API | ๊ณผ๊ฑฐ ๋ ์จ(์ต๋ 1940๋ ๋~ํ์ฌ) (Open Meteo) |
| Climate API | ์ฅ๊ธฐ ๊ธฐํ ๋ฐ์ดํฐ/๋ชจ๋ธ ๊ธฐ๋ฐ ํต๊ณ (Open Meteo) |
| Marine Weather API | ํด์ ๊ธฐ์/ํ๋/์กฐ์ ๋ฐ์ดํฐ (Open Meteo) |
| ECMWF API | ์ ๋ฝ์ค๊ธฐ์๋ณด์ผํฐ ๋ชจ๋ธ ๊ธฐ๋ฐ ์๋ณด (Open Meteo) |
| MET Norway API | ๋ถ์ ๋ฝ ์ง์ญ 1km๊ธ ๋จ๊ธฐ ์๋ณด (Open Meteo) |
GET https://api.open-meteo.com/v1/forecast
๋ชจ๋ ๋ฐ์ดํฐ๋ Query Parameter๋ก ์ ๋ฌํจ
| ํ๋ผ๋ฏธํฐ | ์ค๋ช |
|---|---|
latitude | ์๋ |
longitude | ๊ฒฝ๋ |
?latitude=37.57&longitude=126.98
์ขํ๊ณ๋ WGS84 (์ผ๋ฐ์ ์ธ GPS ์ขํ)
Weather Forecast API๋ ํฌ๊ฒ 3์ข ๋ฅ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณต
ํ์ฌ ์๊ฐ ๊ธฐ์ค์ ์ค์๊ฐ ๋ ์จ
current= ํ๋ผ๋ฏธํฐ ์ฌ์ฉ
¤t=temperature_2m,weathercode,wind_speed_10m
| ๋ณ์ | ์ค๋ช |
|---|---|
temperature_2m | ํ์ฌ ๊ธฐ์จ (2m ๋์ด) |
weathercode | ๋ ์จ ์ํ ์ฝ๋ |
wind_speed_10m | ํ์ |
is_day | ๋ฎ/๋ฐค ์ฌ๋ถ (1 / 0) |
๋ณดํต 48~72์๊ฐ ์ด์
1์๊ฐ ๋จ์ ๋ฐ์ดํฐ
&hourly=temperature_2m,precipitation_probability,wind_speed_10m
| ๋ณ์ | ์ค๋ช |
|---|---|
temperature_2m | ๊ธฐ์จ |
relative_humidity_2m | ์ต๋ |
apparent_temperature | ์ฒด๊ฐ ์จ๋ |
precipitation | ๊ฐ์๋ |
precipitation_probability | ๊ฐ์ ํ๋ฅ |
weathercode | ๋ ์จ ์ฝ๋ |
cloudcover | ๊ตฌ๋ฆ๋ |
wind_speed_10m | ํ์ |
wind_direction_10m | ํํฅ |
์ต๋ 16์ผ
ํ๋ฃจ ์์ฝ ๋ฐ์ดํฐ (์ต๊ณ /์ต์ ๋ฑ)
&daily=temperature_2m_max,temperature_2m_min,weathercode
| ๋ณ์ | ์ค๋ช |
|---|---|
temperature_2m_max | ์ต๊ณ ๊ธฐ์จ |
temperature_2m_min | ์ต์ ๊ธฐ์จ |
precipitation_sum | ์ผ ๊ฐ์๋ |
precipitation_probability_max | ์ต๋ ๊ฐ์ ํ๋ฅ |
sunrise / sunset | ์ผ์ถ / ์ผ๋ชฐ |
uv_index_max | ์ต๋ ์์ธ์ ์ง์ |
weathercode | ์ผ๋ณ ๋ ์จ ์ํ |
| ์ฝ๋ | ์๋ฏธ |
|---|---|
| 0 | ๋ง์ |
| 1~3 | ๋์ฒด๋ก ๋ง์ / ๊ตฌ๋ฆ |
| 45, 48 | ์๊ฐ |
| 51~57 | ์ด์ฌ๋น |
| 61~67 | ๋น |
| 71~77 | ๋ |
| 80~82 | ์๋๊ธฐ |
| 95 | ์ฒ๋ฅ๋ฒ๊ฐ |
static const String _baseUrl = 'https://api.open-meteo.com/v1/forecast';
final uri = Uri.parse(
'$_baseUrl?latitude=$latitude&longitude=$longitude'
'&timezone=auto¤t=temperature_2m,is_day,wind_speed_10m,weather_code',
);
static const String _baseUrl = 'https://api.open-meteo.com/v1/forecast';
Open-Meteo Weather Forecast API ์๋ํฌ์ธํธ
๋ชจ๋ ๋ ์จ ์๋ณด ์์ฒญ์ ์ด URL์์ ์์ํจ
โ์ด๋์ ์์ฒญํ ์งโ ์ ์
์์ฒญํ ์์น์ ์๋
๋ถ์: ์์ / ๋จ์: ์์
latitude = 37.57 โ ์์ธ ๊ทผ์ฒ
๐ ๋ ์จ๋ฅผ ์กฐํํ ์ธ๋ก ์์น
์์ฒญํ ์์น์ ๊ฒฝ๋
๋๊ฒฝ: ์์ / ์๊ฒฝ: ์์
longitude = 126.98 โ ์์ธ ๊ทผ์ฒ
๐ ๋ ์จ๋ฅผ ์กฐํํ ๊ฐ๋ก ์์น
&timezone=auto
ํด๋น ์ขํ์ ๋ง๋ ํ์ง ์๊ฐ๋ ์๋ ์ ์ฉ
์: ํ๊ตญ โ Asia/Seoul
๋ ์ง / ์๊ฐ ๊ณ์ฐ์ ์๋ฒ๊ฐ ์๋์ผ๋ก ๋ง์ถฐ์ค
current.time, daily.time ๋ฑ์ด ๋ก์ปฌ ์๊ฐ ๊ธฐ์ค
์ฑ์์ ์๊ฐ ๋ณํ ์ ํด๋ ๋ผ์ ๋งค์ฐ ํธํจ
¤t=temperature_2m,is_day,wind_speed_10m,weather_code
ํ์ฌ ์๊ฐ์ ๋ ์จ ๋ฐ์ดํฐ๋ง ์์ฒญ
Open-Meteo๋ current, hourly, daily๋ฅผ ๋ช
์ํ์ง ์์ผ๋ฉด ์ ์ค
์ง๋ฉด ์ 2m ๊ธฐ์ค ๊ธฐ์จ
์ฐ๋ฆฌ๊ฐ ์ผ๋ฐ์ ์ผ๋ก ๋งํ๋ โํ์ฌ ๊ธฐ์จโ
ํ์ฌ ์๊ฐ์ด ๋ฎ์ธ์ง ๋ฐค์ธ์ง
| ๊ฐ | ์๋ฏธ |
|---|---|
1 | ๋ฎ |
0 | ๋ฐค |
์ง๋ฉด ์ 10m ๊ธฐ์ค ํ์
์ฒด๊ฐ ์จ๋, ๋ฐ๋ UI์ ํ์ฉ
ํ์ฌ ๋ ์จ ์ํ๋ฅผ ์ซ์๋ก ํํ
String _convertWeatherCode(num code) {
final int c = code.toInt();
if (c == 0) return '๋ง์';
if ([1, 2, 3].contains(c)) return '๋ถ๋ถ ํ๋ฆผ ๋๋ ๊ตฌ๋ฆ ๋ง์';
if ([45, 48].contains(c)) return '์๊ฐ';
if ([51, 53, 55].contains(c)) return '์ด์ฌ๋น';
if ([56, 57].contains(c)) return '์ธ ์ด์ฌ๋น';
if ([61, 63, 65].contains(c)) return '๋น';
if ([66, 67].contains(c)) return '์ธ ๋น';
if ([71, 73, 75].contains(c)) return '๋';
if (c == 77) return '๋์ก์ด';
if ([80, 81, 82].contains(c)) return '์๋๊ธฐ';
if ([85, 86].contains(c)) return '๋ ์๋๊ธฐ';
if (c == 95) return '์ฒ๋ฅ ๋ฒ๊ฐ';
if ([96, 99].contains(c)) return '๋ฒ๊ฐ์ ์ฐ๋ฐ';
return '์ ์ ์์';
}
๊ณผ์ ์งํํ๋ฉด์ ๊ฐ์ธ์ ์ผ๋ก ๋ถ์กฑํ ๋ถ๋ถ๊ณผ ์๋ก์ด api๋ฅผ ๊ณต๋ถํ๋ค. ์ด์ ๊ณผ์ ๋ง๋ฌด๋ฆฌํ๊ณ ๋จ์ ๊ฐ์ ๋ค์ด๋ด์ผ๊ฒ ๋ค!