ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Flutter: 날씨 앱(weather app) 만들기 2: JSON parsing
    공부 기록/Flutter 2022. 1. 6. 23:43
    728x90

    https://www.youtube.com/watch?v=ccq1yCmNzdk&list=PLQt_pzi-LLfoOpp3b-pnnLXgYpiFEftLB&index=14 

    #1에서는 버튼을 누르면 날씨 정보를 가져왔는데, 앱이 실행되자마자 날씨 정보가 나타나도록 코드를 바꿔보자. 
    onPressed를 null로 바꾸고, initState() 사용 

    class _LoadingState extends State<Loading> {
    
      // _LoadingState 위젯이 생성될 때 딱 한번 호출되는 메서드 추가
      @override
      void initState() {
        super.initState();
            getLocation(); //initState 안에 추가함으로써 앱이실행되지마자 위치 정보가 뜰 수 있도록 수정함
      }
    
      void getLocation() async {
        // 현재 위치 가져오기
        Position position = await Geolocator.getCurrentPosition(
            desiredAccuracy: LocationAccuracy.high);
        print(position);
      }

    인터넷이 안되거나 위치정보 동의를 거부하는 경우와 같이 예외적인 상황을 위해 exeption handling 필요 -> try-catch문 사용. 예외의 경우는 일반적으로 'e'를 사용하는데, 다른 걸로 사용해도 괜찮음.

    에러가 발생하지 않고 메시지가 출력되도록.

     

    https://pub.dev/packages/http/install을 참고해 http package 설치.
    공식 문서 참고하여 인터넷 허용까지 추가.

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.weather">
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> // 이전에 추가해둔 위치 동의
        <uses-permission android:name="android.permission.INTERNET" /> //인터넷 허용 동의

     

    fetchData() 추가. get에 마우스를 올려보면 어떤 형태로 써야하는지 나옴.

    문서를 보면, get()은 지정한 헤더들을 지정한 URL로 GET 요청을 보내는 함수이다. URL은 URI보다 더 작은 개념. 

     

    API Reference > HTTP > Response를 살펴보면, Response란 미리 알려진 전체 응답 바디에 있는 HTTP 응답 클래스라고 한다.  여기서 새로운 인스턴스를 생성하고, 다양한 Properties를 이용하여 데이터를 사용할 수 있다. 

    예를 들어, body 속성을 이용하면, 응답 바디 전체가

    statusCode를 이용하면 상태코드가 나타난다. 

     

    package 에 as http를 추가하여, get이 http 패키지로부터 왔다는 것을 명시 + get 함수를 불러올 때도 http. 표시해야함

    이렇게 표기해줌으로써, 다른개발자가 은 http.Response를 보고 http 패키지로부터 나온 것을 파악한 후, 문서(> API reference)에서 이의 Response에 대한 정보를 확인할 수 있음

    데이터 형식에 대해 알아보자면, XML은 html 태그와 비슷한데 (<p> <br>...), 다른 점은 사용자 임의로 태그를 만들고 키와 값을 설정하여 메타 정보를 추가할 수 있다. (오른쪽 그림 예시 참고)

    JSON parsing을 해보자.  요청 성공시 (상태 코드 200) reponse body를 가져오고, 실패 시 에러메시지를 띄우도록.

    - import 'dart:convert'; 문 추가 -> jsonDecode() 메서드를 사용할 수 있게됨. 인자값으로 응답 바디를 선언한 jsondata 변수를 전달해주자.
    - myJson이라는 변수에 jsonDecode() 함수 호출  weather의 0번 인덱스에 있는 데이터 중 description을 가져와보자. 
      ㄴJSON의 값은 string, int 등 어떤 타입이 올지 모르므로 Dynamic 타입으로 지정해주어야 하기 때문에 변수 키워드를 'var'로 지정해주어야 한다.
      ㄴ 이 때 특이한 것은, jsonDecode(변수)['weather'][0]['description']; 형식으로 작성.

    Troubleshooting: 여기서 나는  await get() 부분에서 에러가 발생하였다. 
    -> http 버전을 강의에서 사용한 버전(http: ^0.12.2)으로 바꾸었더니, "Error: Cannot run with sound null safety, because the following dependencies don't support null safety: - package:http - package:http_parser"가 발생하였다.  null safety가 적용된 버전이라 그런 것 같다. . 이 블로그를 참고해서 안드로이드 스튜디오에서 --no-sound-null-safety 를 설정하니, 빌드가 잘 되었다!

    의문) 왜 instance of 'Response'가 보이지?   Future<void> getLocation() async 에 Future를 붙여봐도 동일하네 +_+

    // import 'dart:html';
    import 'dart:core';
    import 'package:flutter/material.dart';
    import 'package:geolocator/geolocator.dart';
    import 'package:http/http.dart' as http; // http
    import 'dart:convert';
    
    class Loading extends StatefulWidget {
      const Loading({Key? key}) : super(key: key);
    
      @override
      _LoadingState createState() => _LoadingState();
    }
    
    class _LoadingState extends State<Loading> {
    
      // _LoadingState 위젯이 생성될 때 딱 한번 호출되는 메서드 추가
      @override
      void initState() {
        super.initState();
        getLocation(); //initState 안에 추가함으로써 앱이실행되지마자 위치 정보가 뜰 수 있도록 수정함
        fetchData();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: ElevatedButton(
              onPressed: null,
              child: Text('Get my location'),
            ),
          ),
        );
      }
    
      void fetchData() async {
    
        http.Response response = await http.get('https://samples.openweathermap.org/data/2.5/weather?q=London&appid=b1b15e88fa797225412429c1c50c122a1');
        print(response);
    
        if(response.statusCode == 200){
          String jsonDada = response.body; // 성공하면 응답 바디를 가져옴
          var myJson = jsonDecode(jsonDada)['weather'][0]['description']; // weather[0]의 description만 가져옴
          var windSpeed = jsonDecode(jsonDada)['wind']['speed'];
          print(jsonDada);
          print(myJson);
          print(windSpeed);
        } else (response.statusCode); // 성공하지 않으면 상태코드를 보여줌 
      }
    
      Future<void> getLocation() async {
        try {
          Position position = await Geolocator.getCurrentPosition(
              desiredAccuracy: LocationAccuracy.high);
          print(position);
        } catch (e) {
          print('Internet connect problem');
        }
        //
        // void requestPermission() async {
        //   //권한 요청하기
        //   LocationPermission permission = await Geolocator.requestPermission();
        // }
      }
    }

    댓글

Designed by Tistory.