Skip to content

Application using flutter that displays the weather on the calendar and recommends clothes and food for the weather

Notifications You must be signed in to change notification settings

yhj0329/today_weather

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

today_weather

공공 데이터인 날씨 api를 사용하여 달력에 기온 등을 표시하고
해당 날씨에 맞는 옷차림과 음식을 추천해주는 App이다.

default.mp4

목차

async & await

비동기를 사용하기 위해 async & await 개념을 flutter에서 사용한다.
비동기를 사용하는 목적은 외부에서 data를 조작할 수 있도록 하기 위해서이다.
비동기화는 외부에서 데이터를 가져오는 동안 다른 작업을 수행하다
비동기화를 사용한 데이터가 준비완료 된다면 사용하는 방식이다.

  1. Flutter에서 비동기를 사용할 때 Future, async, await를 사용한다.
  2. 함수 이름 앞 Future은 비동기의 반환을 나타낸다. 가독성을 위해 적는것을 추천하지만, 생략해도 무방하다.
  3. await를 사용하기 위해서는 반드시 async가 적혀있어야한다.
  4. await를 사용하면 비동기 함수가 끝날때까지 기다리며, await를 사용하지않으면 기다리지않는다.
  5. 비동기함수가 끝났음을 알리고싶다면 Callback함수를 이용하여 알릴 수 있다.
  • 사용 코드
Future<void> method async {
    var temp = await something_method;
}

async-await에서 자세한 정보를 알 수 있다.

Flutter Widget끼리 데이터 전달하기

  • 전달하기

loading.dart

import 'package:provider/provider.dart';

void getInfo () async{
    WeatherInfo info = WeatherInfo();
    await info.loadLocation();
    await info.loadWeatherInfo();
    await info.loadPastWeatherInfo(DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day-2));

    if(!mounted) return; // widget이 화면에 장착되면 mounted는 true
    Navigator.push(context, // widget 화면 변경시 Navigator
        MaterialPageRoute(builder:
            (context) => MaterialApp(
          home: Provider( // Provider로 데이터를 전달할 수 있다.
          create: (context) => info, // info 라는 변수를 TodayWeather에게 전달한다
          child: TodayWeather()))));
  }
  • 사용하기

weather.dart, food.dart, clothes.dart

// Provider.of<WeatherInfo>(context) 자체가 loading.dart의 info 변수가 되는 것이다.
Provider.of<WeatherInfo>(context).원하는 변수 또는 메소드

위치 정보 확인

location.dart

import 'package:geolocator/geolocator.dart'; // 위치 정보 가져오기
import 'package:permission_handler/permission_handler.dart'; // 위치 권한 가져오기

class MyLocation {
  late double myLatitude;
  late double myLongitude;

  Future<void> getMyCurrentLocation() async {

    var statusLocation = await Permission.location.request(); // 권한 요청

    if (statusLocation.isGranted) // 권한이 있다면
    {
      // 위치 정보 요청하기
      Position position = await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);

      myLatitude = position.latitude;
      myLongitude = position.longitude;

    }
    else
    {
      print("위치 권한이 필요합니다.");
    }
  }


}

날씨 API

  • API 정보 가져오기

network.dart

import 'dart:convert'; // Json 파일 다루기
import 'package:http/http.dart' as http; // http에서 api 정보 가져오기

class Network {
  late String url;
  Network(this.url); // 생성자

  Future<dynamic> getJsonData() async{
    http.Response response = await http.get(Uri.parse(url)); // url을 통해 Json 데이터 가져오기
    if (response.statusCode == 200)
    {
      String jsonData = response.body;
      var parsingData = jsonDecode(jsonData);
      return parsingData;
    }
    else
    {
      print("error");
    }
  }
}
기상청 데이터를 요청하기 위해 필요한 데이터 변환

현재 위치 좌표를 기상청 위치 좌표로 변환

class ConvGridGps {
  static const double RE = 6371.00877; // 지구 반경(km)
  static const double GRID = 5.0; // 격자 간격(km)
  static const double SLAT1 = 30.0; // 투영 위도1(degree)
  static const double SLAT2 = 60.0; // 투영 위도2(degree)
  static const double OLON = 126.0; // 기준점 경도(degree)
  static const double OLAT = 38.0; // 기준점 위도(degree)
  static const double XO = 43; // 기준점 X좌표(GRID)
  static const double YO = 136; // 기1준점 Y좌표(GRID)

  static const double DEGRAD = Math.pi / 180.0;
  static const double RADDEG = 180.0 / Math.pi;

  static double get re => RE / GRID;

  static double get slat1 => SLAT1 * DEGRAD;

  static double get slat2 => SLAT2 * DEGRAD;

  static double get olon => OLON * DEGRAD;

  static double get olat => OLAT * DEGRAD;

  static double get snTmp =>
      Math.tan(Math.pi * 0.25 + slat2 * 0.5) /
          Math.tan(Math.pi * 0.25 + slat1 * 0.5);

  static double get sn =>
      Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(snTmp);

  static double get sfTmp => Math.tan(Math.pi * 0.25 + slat1 * 0.5);

  static double get sf => Math.pow(sfTmp, sn) * Math.cos(slat1) / sn;

  static double get roTmp => Math.tan(Math.pi * 0.25 + olat * 0.5);

  static double get ro => re * sf / Math.pow(roTmp, sn);

  static gridToGPS(int v1, int v2) {
    var rs = {};
    double theta;

    int xn = (v1 - XO).toInt();
    int yn = (ro - v2 + YO).toInt();
    var ra = Math.sqrt(xn * xn + yn * yn);
    if (sn < 0.0) ra = -ra;
    var alat = Math.pow((re * sf / ra), (1.0 / sn));
    alat = 2.0 * Math.atan(alat) - Math.pi * 0.5;

    if (xn.abs() <= 0.0) {
      theta = 0.0;
    } else {
      if (yn.abs() <= 0.0) {
        theta = Math.pi * 0.5;
        if (xn < 0.0) theta = -theta;
      } else
        theta = Math.atan2(xn, yn);
    }
    var alon = theta / sn + olon;
    rs['lat'] = alat * RADDEG;
    rs['lng'] = alon * RADDEG;

    return rs;
  }

  static gpsToGRID(double v1, double v2) {
    var rs = {};
    double theta;

    var ra = Math.tan(Math.pi * 0.25 + (v1) * DEGRAD * 0.5);
    ra = re * sf / Math.pow(ra, sn);
    theta = v2 * DEGRAD - olon;
    if (theta > Math.pi) theta -= 2.0 * Math.pi;
    if (theta < -Math.pi) theta += 2.0 * Math.pi;
    theta *= sn;
    rs['x'] = (ra * Math.sin(theta) + XO + 0.5).floor();
    rs['y'] = (ro - ra * Math.cos(theta) + YO + 0.5).floor();

    return rs;
  }
}

좌표로 주소 찾고 기상청 주소 코드로 변환하기

const Map<String, String> LocationCode = {
  "서울" : "11B00000",
  "인천" : "11B00000",
  "경기도" : "11B00000",
  "강원" : "11D10000",
  "대전" : "11C20000",
  "세종" : "11C20000",
  "충청남도" : "11C20000",
  "충청북도" : "11C10000",
  "광주광역시" : "11F20000",
  "전라남도" : "11F20000",
  "전라북도" : "11F10000",
  "대구" : "11H10000",
  "경상북도" : "11H10000",
  "부산" : "11H20000",
  "울산" : "11H20000",
  "경상남도" : "11H20000",
  "제주" : "11G00000",
};

myAddress = await Network('https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=$myLongitude&y=$myLatitude ').getRestAPIJsonData(restApiKey); // 나의 좌표를 입력하면 주소로 변환하는 카카오 API를 사용

LocationCode.forEach((key, value) { // Map 데이터인 LocationCode를 반복한다.
if (myAddress['documents'][0]['address_name'].contains(key)){ // 주소로 변환된 곳에 알맞는 key가 있다면 
    myAddressCode = value; // 그 코드를 변수에 담는다.
}
});

Loading 화면 만들기

loading.dart

import 'package:flutter_spinkit/flutter_spinkit.dart';

flutter_spinkit을 활용하여 만들 수 있다.

힘들었던 점

  • API 데이터를 flutter widget끼리 주고 받는 과정이 어려웠다.
  • 날씨 API의 데이터의 형식이 일정하지 않았기 때문에 데이터 처리가 번거로웠다.

About

Application using flutter that displays the weather on the calendar and recommends clothes and food for the weather

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published