조금 매운맛 13 날씨앱 만들기 1
기능
- 위치 정보 사용 허락
- 날씨, 날짜, 시간 화면 표시
- 검색으로 원하는 지역 날씨 확인
위젯의 Life cycle(생명주기)
1. Stateless Widget
- 한번 생성되면 바뀌지 않는다.
- 바꿀려면 위젯을 완전히 파괴(destroy) 하고 새롭게 빌드(rebuild)해야함
- build method 만 신경쓰면 됨.
2. State Widget
- state object와 결합하여 setstate 메소드를 통해서 원하는 구성요소나 속성변수를 언제나 업데이트 할 수 있음
- Stateful widgets live longer thatn stateless widgets (
Stateless Widget 보다 좀더 긴 생명주기를 가짐)- 대표적인 생명주기 메소드1) initState method : state가 최초로 초기화 될때 호출2) build method3) dispose method / deactivate method : state가 파괴될때 호출
순한맛23 push named 파일 사용
//ScreenB.dart
import 'package:flutter/material.dart';
class ScreenB extends StatefulWidget {
@override
State<ScreenB> createState() => _ScreenBState();
}
class _ScreenBState extends State<ScreenB> {
@override
void initState() { //Statefulwidget이 생성될떄(=앱이 실행될떄) 기능이 실행되길 바라면 여기에 구현, 호출
// TODO: implement initState
super.initState();
print('initState is called');
}
@override
void dispose() { //위젯이 위젯트리에서 완전히 제거될때
// TODO: implement dispose
super.dispose();
print('dispose is called');
}
@override
Widget build(BuildContext context) {
print('build is called');
return Scaffold(
appBar: AppBar(
title: Text('ScreenB'),
),
body: Center(
child: Text(
'ScreenB',
style: TextStyle(
fontSize: 24.0
),
)
)
);
}
}
> 앱 실행해서 스크린B로 가면 initState 메소드와 build 메소드 호출
다시 스크린A로 가면 dispose 메소드가 호출되 사라짐
날씨앱 만들기 기본 코드
//main.dart
import 'package:flutter/material.dart';
import 'screens/loading.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Weather app',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Loading(),
);
}
}
//screens/loading.dart
import 'package:flutter/material.dart';
class Loading extends StatefulWidget {
const Loading({Key? key}) : super(key: key);
@override
State<Loading> createState() => _LoadingState();
}
class _LoadingState extends State<Loading> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: (){
},
child: Text('get my location'),
),
),
);
}
}
API : Application Programming Interface
응용 프로그램에서 사용할 수 있도록 운영체제나 프로그램이 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스
API 종류
1. 일련의 표준화된 명령이나 기능
: appbar 등 앱에서 실행되는 일반적인 작업들을 구현하기 위해서 개발자가 일일이 코딩할 필요없이 표준화된 명령어를 통해 쉽게 수행할 수 있는 것.
2. 매개 역할자로써의 API
: 은행에 가서 통장번호, 비밀번호를 건네서 돈을 찾는 것과 비슷한 이치.
주로 소량의 데이터를 요구하지만 때때로 많은 데이터를 요구할 때가 있음.
이걸 전부 전송하면 서버에 과부하가 올 수 있기에 키값(은행창구 직원)를 이용해서 사용자(고객)를 확인하고 일정량의 데이터(돈)를 줌
주로 제한사항 = 규칙을 가지고 있음.
만약 키값이 틀리면 404 에러 보냄
> 즉, API를 통해 파라미터를 전달하면서 데이터를 요구하면 그것이 유효할 경우 API는 우리에게 데이터를 전송하게 됨. 이때 유효하지 않으면 404 에러 발생
날씨 API 사용할 웹페이지 https://openweathermap.org/
◼ 그전에 현재 사용자의 위치를 가져올수 있는 flutter package 설치 https://pub.dev/packages/geolocator
1. 패키지 코드 pubspec.yaml 파일에 복붙
2. 설치한 패키지 사용을 위해 import
//loading.dart
import 'package:geolocator/geolocator.dart';
◼ 현재 위치 가져오기
//loading.dart
//현재 위치 정보 얻기
void getLocation() async{ //await은 async 방식이니 추가해줘야함
Position position = await Geolocator.
getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
}
위치 정보 수집 동의를 받아야함
◼ AndroidManifest.xml의 가장 상단 aminfest 밑에 붙여넣기
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
이후 앱실행 시키면 콘솔창에 위도,경도가 잘 뜸
> 나는 안뜸 쌰갈
1. 앱 내 build.gradle 가서 compileSdkVersion 버전을 수정해줘야함 (23년 2월 기준 33으로 해야 에러가 안 남)
2. getLocation 메소드에 코드 추가
LocationPermission permission = await Geolocator.requestPermission();
그럼 코드가 잘 뜬다.
조금매운맛13 최종코드
//loading.dart
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class Loading extends StatefulWidget {
const Loading({Key? key}) : super(key: key);
@override
State<Loading> createState() => _LoadingState();
}
class _LoadingState extends State<Loading> {
//현재 위치 정보 얻기
void getLocation() async{ //await은 async 방식이니 추가해줘야함
LocationPermission permission = await Geolocator.requestPermission();
Position position = await Geolocator.
getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: (){
getLocation();
},
child: Text('get my location'),
),
),
);
}
}
조금 매운맛 14 날씨 앱 만들기2 : JSON parsing
터널 등 위치가 잘 잡히지 않거나 위치 공유를 거절할 경우를 대비해 try ~ catch 문 이용
void getLocation() async{
try{
LocationPermission permission = await Geolocator.requestPermission();
Position position = await Geolocator.
getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
}catch(e){
print('There was a problem with the internet connection.');
}
}
◼ 데이터 가져오기 위한 준비
1. http 패키지 설치 https://pub.dev/packages/http
1) pubspec.yaml
http: ^0.13.5
2) loading.dart 맨위 import
//loading.dart
import 'package:http/http.dart';
3) AndroidManifest.xml
https://docs.flutter.dev/cookbook/networking/fetch-data 참조
<uses-permission android:name="android.permission.INTERNET" />
* http get메소드는 인자값으로 uri나 string를 가지고 있음
(URI가 URL을 내포하고 있음. url는 uri의 한 종류)
◼ fetchdata 메소드 생성
void fetchData() async {
Response response = await get(Uri.parse(
'https://samples.openweathermap.org/data/2.5/weather?
q=London&appid=b1b15e88fa797225412429c1c50c122a1'));
}
>임의로 더미데이터 넣어서 확인. 더미데이터를 resopnse 변수에 담음
인터넷으로 openweather로 접속해서 미래의 시점의 데이터를 모두 가져올떄까지 기다려야하기 때문에 await 키워드 사용
> 하지만 데이터는 안 들어오고 response라는 인스턴스만 출력됨
> 우리가 가져오는 데이터는 응답되는 순간 생성되는 것이 아니라 이미 만들어진 것
이미 정영화된 데이터를 가져오는 것이고 이때 새로운 response 인스턴스를 생성하면 다양한 속성으로 데이터를 변형해야함
print(response.body);
> 데이터 전문을 불러오는 body 사용
결과
> 이런 형식을 JSON 형식이라 함
api에 전달/응답용 데이터로 사용
JSON | XML |
Javascript Object Notation | eXtensibel Markup Language |
키값과 밸류값을 1대1 맵핑 | HTML 코드와 유사 |
<key> value </key> 와 같이 사용자가 태그를 만들 수 있음 (html은 <p>, </p>, <h1>, </h1> . . . 약속한 태그들만 사용가능) |
|
{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":300,"main":"Drizzle","description":"light intensity drizzle","icon":"09d"}], | <st:profile> <pf:html> <pf:head> <pf:title>빨간색코딩</pf:title> </pf:head> <pf:body>개발해서 내집장만</pf:body> </pf:html> </st:profile> |
+ 크롬 웹스토어에서 다운
> json을 좀더 가독성 있게 만들어주는 확장 프로그램
◼ Json Parsing
fetchData 메소드에 추가
if(response.statusCode ==200){
String jsonData = response.body;
}
> weather 안의 인덱스 0번째의 description 출력 하기
// loading.dart 상단
import 'dart:convert';
//fetchdata() 안
var myJson = jsonDecode(jsonData)['weather'][0]['description'];\
print(myJson);
* Json 데이터의 타입은 예측할 수 없음
그래서 jsonDecode의 타입은 dynamic으로 되어 있음
변수에 담을 때 var를 사용해야함
조금매운맛14 전체 코드
//loading.dart
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Loading extends StatefulWidget {
const Loading({Key? key}) : super(key: key);
@override
State<Loading> createState() => _LoadingState();
}
class _LoadingState extends State<Loading> {
@override
void initState() {
// TODO: implement initState
super.initState();
getLocation();
fetchData();
}
void fetchData() async {
http.Response response = await http.get(Uri.parse(
'https://samples.openweathermap.org/data/2.5/weather?q=London&appid=b1b15e88fa797225412429c1c50c122a1'));
if(response.statusCode ==200){
String jsonData = response.body;
var myJson = jsonDecode(jsonData)['weather'][0]['description'];
var myWind = jsonDecode(jsonData)['wind']['speed'];
var myId = jsonDecode(jsonData)['id'];
print(myJson);
print(myWind);
print(myId);
}else{
print(response.statusCode);
}
}
//현재 위치 정보 얻기
void getLocation() async{
try{
LocationPermission permission = await Geolocator.requestPermission();
Position position = await Geolocator.
getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position);
}catch(e){
print('There was a problem with the internet connection.');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: (){
null;
},
child: Text('get my location'),
),
),
);
}
}
'공부 > Flutter' 카테고리의 다른 글
Flutter 오류 Entrypoint isn't within the current project (0) | 2023.02.16 |
---|---|
Flutter 스터디 23 날씨 앱 만들기 json 데이터 전달하기, UI 디자인, 데이터 연동 (0) | 2023.02.16 |
Flutter 스터디 21 Flutter 2.0과 Null safety 널 세이프티 (0) | 2023.02.13 |
Flutter 스터디 20 반복문 loop와 추첨 프로그램, Future-async 심화학습 (1) | 2023.02.13 |
Flutter 스터디 19 Future, async, awite, AndroidX migration (0) | 2023.02.09 |