본문 바로가기

Flutter/10 app Weather

[Flutter] App Weather - 3.5단계 model of openweathermap

이번에는 데이터 모델을 만드는 방법에 대해서 알아보겠습니다.

개발환경 : 윈도우11, 안드로이드 스튜디오(Arctic Fox 2020.3.1 Patch 4), flutter 2.8.1

소스코드 위치 - Release data_model · mike-bskim/weather · GitHub

 

Release data_model · mike-bskim/weather

 

github.com

 

데이터 모델을 쉽게 만드는 툴/웹/플러그인들이 있는데, 그중에서 안드로이드 스튜디오에서 추가 가능한 "JsonToDart" 라는 플러그인으로 변환작업을 하였습니다.

 

 

model 폴더를 만들고 우클릭으로 "Json To Dart" 를 실행한다. 이전 블로그에서 사용한 샘플 데이터를 복/붙한다.

주의 사항))) 복/붙할때 주의 사항은 키/값중에 값에 공백이 있는 경우는 반드시 따옴표로 묶어주어야 한다. 복/붙 후, 오른쪽 상단의 "Format" 버튼을 클릭해서 형식이 보기좋게 변하지 않으면 공백이 포함된 값이 있는경우이니 주의하자.

 

 

 

생성된 model/current_weather.dart 파일  파일이 길어서 "더보기" 처리했습니다.

내용을 모두 보려면 "더보기" 클릭하세요.

 

더보기

 

/// coord : {"lon":9.19,"lat":45.4642}
/// weather : [{"id":802,"main":"Clouds","description":"구름조금","icon":"03d"}]
/// base : "stations"
/// main : {"temp":18.73,"feels_like":17.94,"temp_min":17.67,"temp_max":20.4,"pressure":1023,"humidity":49}
/// visibility : 10000
/// wind : {"speed":3.09,"deg":90}
/// clouds : {"all":40}
/// dt : 1651140421
/// sys : {"type":2,"id":2012644,"country":"IT","sunrise":1651119376,"sunset":1651170299}
/// timezone : 7200
/// id : 3173435
/// name : "Milan"
/// cod : 200

class CurrentWeather {

  Coord? _coord;
  List<Weather>? _weather;
  String? _base;
  Main? _main;
  int? _visibility;
  Wind? _wind;
  Clouds? _clouds;
  int? _dt;
  Sys? _sys;
  int? _timezone;
  int? _id;
  String? _name;
  int? _cod;

  CurrentWeather({
    Coord? coord,
    List<Weather>? weather,
    String? base,
    Main? main,
    int? visibility,
    Wind? wind,
    Clouds? clouds,
    int? dt,
    Sys? sys,
    int? timezone,
    int? id,
    String? name,
    int? cod,
  }) {
    _coord = coord;
    _weather = weather;
    _base = base;
    _main = main;
    _visibility = visibility;
    _wind = wind;
    _clouds = clouds;
    _dt = dt;
    _sys = sys;
    _timezone = timezone;
    _id = id;
    _name = name;
    _cod = cod;
  }

  CurrentWeather.fromJson(dynamic json) {
    _coord = json['coord'] != null ? Coord.fromJson(json['coord']) : null;
    if (json['weather'] != null) {
      _weather = [];
      json['weather'].forEach((v) {
        _weather?.add(Weather.fromJson(v));
      });
    }
    _base = json['base'];
    _main = json['main'] != null ? Main.fromJson(json['main']) : null;
    _visibility = json['visibility'];
    _wind = json['wind'] != null ? Wind.fromJson(json['wind']) : null;
    _clouds = json['clouds'] != null ? Clouds.fromJson(json['clouds']) : null;
    _dt = json['dt'];
    _sys = json['sys'] != null ? Sys.fromJson(json['sys']) : null;
    _timezone = json['timezone'];
    _id = json['id'];
    _name = json['name'];
    _cod = json['cod'];
  }


  Coord? get coord => _coord;

  List<Weather>? get weather => _weather;

  String? get base => _base;

  Main? get main => _main;

  int? get visibility => _visibility;

  Wind? get wind => _wind;

  Clouds? get clouds => _clouds;

  int? get dt => _dt;

  Sys? get sys => _sys;

  int? get timezone => _timezone;

  int? get id => _id;

  String? get name => _name;

  int? get cod => _cod;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    if (_coord != null) {
      map['coord'] = _coord?.toJson();
    }
    if (_weather != null) {
      map['weather'] = _weather?.map((v) => v.toJson()).toList();
    }
    map['base'] = _base;
    if (_main != null) {
      map['main'] = _main?.toJson();
    }
    map['visibility'] = _visibility;
    if (_wind != null) {
      map['wind'] = _wind?.toJson();
    }
    if (_clouds != null) {
      map['clouds'] = _clouds?.toJson();
    }
    map['dt'] = _dt;
    if (_sys != null) {
      map['sys'] = _sys?.toJson();
    }
    map['timezone'] = _timezone;
    map['id'] = _id;
    map['name'] = _name;
    map['cod'] = _cod;
    return map;
  }
}

/// type : 2
/// id : 2012644
/// country : "IT"
/// sunrise : 1651119376
/// sunset : 1651170299

class Sys {

  int? _type;
  int? _id;
  String? _country;
  int? _sunrise;
  int? _sunset;

  Sys({
    int? type,
    int? id,
    String? country,
    int? sunrise,
    int? sunset,
  }) {
    _type = type;
    _id = id;
    _country = country;
    _sunrise = sunrise;
    _sunset = sunset;
  }

  Sys.fromJson(dynamic json) {
    _type = json['type'];
    _id = json['id'];
    _country = json['country'];
    _sunrise = json['sunrise'];
    _sunset = json['sunset'];
  }

  int? get type => _type;

  int? get id => _id;

  String? get country => _country;

  int? get sunrise => _sunrise;

  int? get sunset => _sunset;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['type'] = _type;
    map['id'] = _id;
    map['country'] = _country;
    map['sunrise'] = _sunrise;
    map['sunset'] = _sunset;
    return map;
  }
}

/// all : 40

class Clouds {

  int? _all;

  Clouds({
    int? all,
  }) {
    _all = all;
  }

  Clouds.fromJson(dynamic json) {
    _all = json['all'];
  }

  int? get all => _all;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['all'] = _all;
    return map;
  }
}

/// speed : 3.09
/// deg : 90

class Wind {
  double? _speed;
  int? _deg;

  Wind({
    double? speed,
    int? deg,
  }) {
    _speed = speed;
    _deg = deg;
  }

  Wind.fromJson(dynamic json) {
    _speed = json['speed'];
    _deg = json['deg'];
  }

  double? get speed => _speed;

  int? get deg => _deg;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['speed'] = _speed;
    map['deg'] = _deg;
    return map;
  }
}

/// temp : 18.73
/// feels_like : 17.94
/// temp_min : 17.67
/// temp_max : 20.4
/// pressure : 1023
/// humidity : 49

class Main {
  double? _temp;
  double? _feelsLike;
  double? _tempMin;
  double? _tempMax;
  int? _pressure;
  int? _humidity;

  Main({
    double? temp,
    double? feelsLike,
    double? tempMin,
    double? tempMax,
    int? pressure,
    int? humidity,
  }) {
    _temp = temp;
    _feelsLike = feelsLike;
    _tempMin = tempMin;
    _tempMax = tempMax;
    _pressure = pressure;
    _humidity = humidity;
  }

  Main.fromJson(dynamic json) {
    _temp = json['temp'];
    _feelsLike = json['feels_like'];
    _tempMin = json['temp_min'];
    _tempMax = json['temp_max'];
    _pressure = json['pressure'];
    _humidity = json['humidity'];
  }

  double? get temp => _temp;

  double? get feelsLike => _feelsLike;

  double? get tempMin => _tempMin;

  double? get tempMax => _tempMax;

  int? get pressure => _pressure;

  int? get humidity => _humidity;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['temp'] = _temp;
    map['feels_like'] = _feelsLike;
    map['temp_min'] = _tempMin;
    map['temp_max'] = _tempMax;
    map['pressure'] = _pressure;
    map['humidity'] = _humidity;
    return map;
  }
}

/// id : 802
/// main : "Clouds"
/// description : "구름조금"
/// icon : "03d"

class Weather {
  int? _id;
  String? _main;
  String? _description;
  String? _icon;

  Weather({
    int? id,
    String? main,
    String? description,
    String? icon,
  }) {
    _id = id;
    _main = main;
    _description = description;
    _icon = icon;
  }

  Weather.fromJson(dynamic json) {
    _id = json['id'];
    _main = json['main'];
    _description = json['description'];
    _icon = json['icon'];
  }

  int? get id => _id;

  String? get main => _main;

  String? get description => _description;

  String? get icon => _icon;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['id'] = _id;
    map['main'] = _main;
    map['description'] = _description;
    map['icon'] = _icon;
    return map;
  }
}

/// lon : 9.19
/// lat : 45.4642

class Coord {
  double? _lon;
  double? _lat;

  Coord({
    double? lon,
    double? lat,
  }) {
    _lon = lon;
    _lat = lat;
  }

  Coord.fromJson(dynamic json) {
    _lon = json['lon'];
    _lat = json['lat'];
  }

  double? get lon => _lon;

  double? get lat => _lat;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['lon'] = _lon;
    map['lat'] = _lat;
    return map;
  }
}

 

 

 

loading.dart 수정

 

import 'package:weather/model/current_weather.dart';

 

  void getLocation() async {
    MyLocation myLocation = MyLocation();

    await myLocation.getMyCurrentLocation();
    latitude = myLocation.latitude;
    longitude = myLocation.longitude;
    debugPrint('loading.dart >> ' + latitude.toString() +' / ' +longitude.toString());

    String baseApi = 'https://api.openweathermap.org/data/2.5/weather';
    Network network = Network(
        '$baseApi?lat=${latitude.toString()}&lon=${longitude.toString()}&appid=$apiKey&units=metric');
    var weatherData = await network.getJsonData();
    debugPrint(weatherData.toString());

	// 추가된 부분 //
    CurrentWeather currentWeather = CurrentWeather.fromJson(weatherData);
    debugPrint(currentWeather.name);
	// 추가된 부분 //

	// weatherData 대신 currentWeather 전달 //
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => WeatherScreen(weatherData: currentWeather)));
  }

 

 

전체 버전은 더보기 클릭 ==>

더보기
import 'package:flutter/material.dart';
import 'package:weather/data/my_location.dart';
import 'package:weather/data/network.dart';
import 'package:weather/model/current_weather.dart';
import 'package:weather/screens/weather_screen.dart';

const apiKey = '1e1a2b8f6d9b5311cd82d001e7b20131';

class Loading extends StatefulWidget {
  const Loading({Key? key}) : super(key: key);

  @override
  _LoadingState createState() => _LoadingState();
}

class _LoadingState extends State<Loading> {
  late double latitude;
  late double longitude;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getLocation();
    // fetchData();
  }

  void getLocation() async {
    MyLocation myLocation = MyLocation();

    await myLocation.getMyCurrentLocation();
    latitude = myLocation.latitude;
    longitude = myLocation.longitude;
    debugPrint('loading.dart >> ' + latitude.toString() +' / ' +longitude.toString());

    String baseApi = 'https://api.openweathermap.org/data/2.5/weather';
    Network network = Network(
        '$baseApi?lat=${latitude.toString()}&lon=${longitude.toString()}&appid=$apiKey&units=metric');
    var weatherData = await network.getJsonData();
    debugPrint(weatherData.toString());

    CurrentWeather currentWeather = CurrentWeather.fromJson(weatherData);
    debugPrint(currentWeather.name);

    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => WeatherScreen(weatherData: currentWeather)));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            debugPrint('ElevatedButton clicked~~');
          },
          child: const Text(
            'Get my location',
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }
}

 

 

 

weather_screen.dart 수정

변수 타입 및 하위 필드 정보 접근 방식이 수정되었다.

 

 

전체 버전은 더보기 클릭 ==>

더보기
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:weather/model/current_weather.dart';

class WeatherScreen extends StatefulWidget {
  final CurrentWeather weatherData;

  const WeatherScreen({Key? key, required this.weatherData}) : super(key: key);

  @override
  State<WeatherScreen> createState() => _WeatherScreenState();
}

class _WeatherScreenState extends State<WeatherScreen> {
  late String cityName;
  late int temp;
  late String currentDate;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    updateData(widget.weatherData);
  }

  void updateData(CurrentWeather weatherData) {
    var dt = weatherData.dt!;
    var timezone = weatherData.timezone!;
    var tempTime = DateTime.fromMillisecondsSinceEpoch((dt+timezone) * 1000);

    cityName = weatherData.name!;
    temp = weatherData.main!.temp!.round();
    currentDate = DateFormat('yyyy-MM-dd, HH:mm:ss').format(tempTime);
    debugPrint('cityName[$cityName], temp[${weatherData.main!.temp}]');
    debugPrint('dt[$dt], timezone[$timezone], Date[$currentDate]');
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(cityName, style: const TextStyle(fontSize: 30)),
              const SizedBox(height: 40),
              Text(currentDate, style: const TextStyle(fontSize: 30)),
              const SizedBox(height: 40),
              Text(temp.toString(), style: const TextStyle(fontSize: 30)),
            ],
          ),
        ),
      ),
    );
  }
}

 

 

 

콘솔로그

 

I/flutter ( 7182): loading.dart >> 45.4642033 / 9.1899817
I/flutter ( 7182): {coord: {lon: 9.1914, lat: 45.4642}, weather: [{id: 800, main: Clear, description: clear sky, icon: 01d}], base: stations, main: {temp: 20.39, feels_like: 19.61, temp_min: 18.39, temp_max: 22.21, pressure: 1022, humidity: 43}, visibility: 10000, wind: {speed: 3.09, deg: 150}, clouds: {all: 0}, dt: 1651147232, sys: {type: 2, id: 2012644, country: IT, sunrise: 1651119376, sunset: 1651170298}, timezone: 7200, id: 3173435, name: Milan, cod: 200}
I/flutter ( 7182): Milan
I/flutter ( 7182): cityName[Milan], temp[20.39]
I/flutter ( 7182): dt[1651147232], timezone[7200], Date[2022-04-28, 14:00:32]

 

 

화면 출력