진동 구조

독자 안녕!여러 해 동안, Flitter는 특히 이동 분야에서 갈수록 유행하고 있다.그것은 배우기 쉬워서 개발 속도를 크게 높일 수 있다.그러나 초보자에게 해결해야 할 문제가 하나 있다. 코드를 어떻게 깨끗하게 하는가?상태를 어떻게 관리합니까?어떻게 코드를 구성합니까?
본고에서 저는 당신에게 코드를 깔끔하게 하는 방법을 보여 드리겠습니다. 물론 이런 구조는 유연하기 때문에 당신은 그것을 변경하거나 편집할 수 있습니다.관심사의 분리를 고려한 것이다.

뭐 공부 해요?


일을 매우 간단하게 하기 위해서, Openweathermapapi를 사용하여 날씨 데이터를 가져오고, 그 중 일부 데이터를 텍스트로 화면에 표시합니다.최종 응용은 다음과 같다.

프로젝트 설정


이 항목은 우리lib 디렉터리에 모두 6개의 폴더가 있습니다
  • 데이터
  • 블렌드
  • 모델
  • 공급업체
  • 스크린
  • UTIL
  • 상태 관리에 대해 우리는 공급자 플러그인을 가진 공급자 모드와 http 호출에 사용되는dio를 사용할 것입니다.그것을 사용하려면,pubspec에 의존항을 추가해야 합니다.yaml 폴더
    공급자 [https://pub.dev/packages/provider]
    Dio[https://pub.dev/packages/dio]

    프로세스


    우리의 응용 프로그램 흐름은 서로 다른 종류로 나뉘어 있으며, 각 종류는 특정한 임무를 수행한다.
    나는 코드를 보여주고 이 종류의 기능을 설명할 것이다. 마지막으로, 나는 전체 과정을 상세하게 설명할 것이다.

    데이터 클래스


    데이터 폴더에서 클래스 2개 weather_dataweather_repo 를 만듭니다.

    The weather_data class is responsible for fetching the weather data from the api, and returning the data to the repo class.
    The getWeather method takes in a dio parameter that will be parse in by the view home_screen.
    When the data has been gotten successfully from the api the weather class feeds the status of the response and the actual data to the Operation class and returns an instance of this class to the Weather Repo


    날씨 데이터


    
    import 'package:dio/dio.dart';
    import 'package:weather_art/models/country_response_model.dart';
    import 'package:weather_art/utils/operation.dart';
    
    class WeatherData{
      Future<Operation> getWeather(Dio dio) async{
    
        try{
          var response = await dio.get(
              'http://api.openweathermap.org/data/2.5/weather?q=lagos&appid={api_key}',
    
          ).timeout(Duration(minutes: 2), onTimeout: () async{
            return Response(
                data: {"message": "Connection Timed out. Please try again"},
                statusCode: 408);
          }).catchError((error) {
            return Response(
                data: {"message": "Error occurred while connecting to server"},
                statusCode: 508);
          });
    
    
          if(response.statusCode == 508 || response.statusCode == 408){
            return Operation(response.statusCode, response.data);
          }else{
    
            WeatherResponse data = WeatherResponse.fromJson(response.data);
    
            return Operation(response.statusCode, data);
          }
    
        }catch(err){
           //catch err
          }
        }
      }
    
    }
    
    final countryData = WeatherData();
    
    weather_repo 클래스는 데이터 클래스를 호출하고 데이터가 되돌아오기를 기다리는 클래스입니다.

    날씨 환매


    import 'package:dio/dio.dart';
    import 'package:weather_art/data/weather_data.dart';
    import 'package:weather_art/utils/operation.dart';
    
    class _WeatherRepo{
       getWeatherData(Dio dio, OperationCompleted countryDataCompleted){
          countryData.getWeather(dio).then((data) => countryDataCompleted(data));
       }
    }
    
    _WeatherRepo countryRepo = _WeatherRepo();
    

    Mixin 클래스


    mixin 폴더에서 클래스를 만들고 이름을 home_helper 로 지정합니다.이 클래스는 공급자와 함께 얻은 데이터에 따라 보기 상태를 변경합니다.이것은 상태를 바꾸는 데 사용되는 코드와 보기 자체를 분리하고 보기에서 실행되는 논리를 감소시켰다
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:weather_art/data/weather_repo.dart';
    import 'package:weather_art/models/country_response_model.dart';
    import 'package:weather_art/providers/home_provider.dart';
    import 'package:weather_art/utils/operation.dart';
    
    mixin HomeHelper{
      BuildContext _authContext;
    
      doGetWeather(Dio dio, BuildContext context){
        _authContext = context;
        Provider.of<HomeProvider>(_authContext, listen: false).updateIsLoading(true);
        weatherRepo.getWeatherData(dio, _weatherDataCompleted);
      }
    
      _weatherDataCompleted(Operation operation){
    
        if(operation.code == 408 || operation.code == 508){
          //handle time out
          Provider.of<HomeProvider>(_authContext, listen: false).updateIsLoading(false);
          print('connection timed out');
        }else{
          WeatherResponse weatherResponse = operation.result;
          Provider.of<HomeProvider>(_authContext, listen: false).updateWeather(weatherResponse);
    
          Provider.of<HomeProvider>(_authContext, listen: false).updateIsLoading(false);
    
        }
      }
    }
    

    모델 클래스


    이 폴더에서 날씨 모델을 생성합니다.
    // To parse this JSON data, do
    //
    //     final weatherResponse = weatherResponseFromJson(jsonString);
    
    import 'dart:convert';
    
    WeatherResponse weatherResponseFromJson(String str) => WeatherResponse.fromJson(json.decode(str));
    
    String weatherResponseToJson(WeatherResponse data) => json.encode(data.toJson());
    
    class WeatherResponse {
      WeatherResponse({
        this.weather,
        this.main,
    
      });
    
      List<Weather> weather;
      Main main;
    
    
      factory WeatherResponse.fromJson(Map<String, dynamic> json) => WeatherResponse(
        coord: Coord.fromJson(json["coord"]),
        weather: List<Weather>.from(json["weather"].map((x) => Weather.fromJson(x))),
        main: Main.fromJson(json["main"]),
    
      );
    
      Map<String, dynamic> toJson() => {
        "coord": coord.toJson(),
        "weather": List<dynamic>.from(weather.map((x) => x.toJson())),
        "main": main.toJson(),
    
      };
    }
    
    class Main {
      Main({
        this.temp,
    
      });
    
      double temp;
    
    
      factory Main.fromJson(Map<String, dynamic> json) => Main(
        temp: json["temp"].toDouble(),
    
      );
    
      Map<String, dynamic> toJson() => {
        "temp": temp,
      };
    }
    
    class Weather {
      Weather({
        this.main,
        this.description,
      });
      String main;
      String description;
    
      factory Weather.fromJson(Map<String, dynamic> json) => Weather(
    
        main: json["main"],
        description: json["description"],
    
      );
    
      Map<String, dynamic> toJson() => {
        "main": main,
        "description": description,
    
      };
    }
    
    

    공급자 폴더


    우리는 이곳에서 두 개의 파일 HomeProviderAppProvider 을 만들었다

    홈 공급업체


    import 'package:flutter/foundation.dart';
    import 'package:weather_art/models/country_response_model.dart';
    
    class HomeProvider extends ChangeNotifier{
      bool isLoading = false;
      List<WeatherResponseModel> weatherList = [];
      WeatherResponseModel weatherResponse;
    
      void updateIsLoading(bool isLoadingGotten){
        isLoading = isLoadingGotten;
        notifyListeners();
      }
    
      void updateWeather(WeatherResponseModel weatherResponseGotten){
        weatherResponse = weatherResponseGotten;
      }
    }
    

    애플리케이션 공급업체


    import 'package:dio/dio.dart';
    
    class AppProvider{
      Dio dio = Dio();
    
    }
    

    Screens 폴더


    이것이 바로 우리의 보기가 있는 위치입니다. 여기서 파일을 만들고 이름을 home_screen 로 지정합니다.
    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:weather_art/mixin/home_helper.dart';
    import 'package:weather_art/providers/app_provider.dart';
    import 'package:weather_art/providers/home_provider.dart';
    
    class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> with HomeHelper{
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
    
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
          doGetWeather(
              Provider.of<AppProvider>(context, listen: false).dio,
              context
          );
        });
    
      }
      @override
      Widget build(BuildContext context) {
        return Consumer(
            builder: (BuildContext context, HomeProvider homeProvider, Widget child){
              return Scaffold(
                body: Container(
                  height: MediaQuery.of(context).size.height,
                  width: MediaQuery.of(context).size.width,
                  child: decideLayout(homeProvider),
                ),
              );
            }
        );
      }
    
      Widget decideLayout(HomeProvider homeProvider){
        if(homeProvider.isLoading){
          return Center(
            child: CircularProgressIndicator(),
          );
        }else if(homeProvider.isLoading == false && homeProvider.weatherResponse == null){
          return Center(
            child: Text(
              'Null',
              style: TextStyle(
                  fontSize: 14
              ),
            ),
          );
        }else{
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Weather in Lagos',
                style: TextStyle(
                    fontSize: 18,
                  fontWeight: FontWeight.bold
                ),
              ),
              Text(
                'Looks Like ${homeProvider.weatherResponse.weather[0].main}',
                style: TextStyle(
                    fontSize: 14
                ),
              ),
    
              Text(
                'Description ${homeProvider.weatherResponse.weather[0].description}',
                style: TextStyle(
                    fontSize: 14
                ),
              ),
    
              Text(
                'Temp ${homeProvider.weatherResponse.main.temp.toString()}',
                style: TextStyle(
                    fontSize: 14
                ),
              ),
            ],
          );
        }
      }
    }
    
    

    utils 폴더


    이 폴더에는 클래스 작업이 포함되어 있습니다.코드에서 복사해서 통과하기만 하면 됩니다.이 클래스는 두 개의 매개 변수를 받아들인다.응답 코드와 응답 데이터.이것은typedef 또는 리셋입니다. 작업이 언제 완료되었는지 확인하는 데 사용됩니다.
    import 'package:flutter/material.dart';
    
    typedef OperationCompleted(Operation operation);
    
    class Operation {
      final dynamic _result;
      final int code;
      Operation(this.code, this._result);
    
      bool get succeeded => code >= 200 && code <= 226;
      dynamic get result => _result;
    }
    
    

    흐르다


    우리는 이미 이 모델에 관련된 모든 코드와 클래스를 보았고 모든 코드와 클래스에 대해 설명을 했습니다. 지금은 모든 코드와 클래스를 연결시켜 사용자와 응용 프로그램의 상호작용을 추적하고 연결점마다 무슨 일이 일어났는지 알려 줍니다.
    한 사용자가 그의 핸드폰 주위를 클릭하여 무엇을 해야 할지 찾은 후에 "오늘 날씨가 어떻게 될지"라고 말했다. 그리고 그는 계속해서 우리의 앱을 열었다.사용자는 우리home_screen를 보게 될 것이며, 우리home_screen는 우리HomeHelper라고 불리는mixin을 사용하고, HomeProvider를 사용하여 자신의 상태를 관리할 것이다.isLoading 클래스의 HomeProvider은false이기 때문에 사용자는 순환 진도를 보고 어떤 내용을 불러오고 있음을 표시합니다.이 경우 initState 필요한 매개 변수 호출doGetWeather을 사용합니다.doGetWeathermixinHomeHelper에서 왔다.doGetWeather류에서 온 weatherRepo.getWeatherData을 호출합니다.이것은 _WeatherRepo 클래스 중의 getWeather 을 호출할 것입니다. 이 클래스는 WeatherData 이기 때문에 이 방법은 Future 에서 일부 내용을 되돌려 주기를 기대합니다.getWeatherapi에서 데이터를 가져와 되돌려줍니다getWeather.Operation 두 개의 매개 변수, 즉 상태 코드와api에서 온 데이터를 받아들인다.작업이 Operation 에서 반환되면 데이터는 뒤로 전달됩니다.
    리포클래스는 리포클래스 getWeather 로 되돌아와 .then 로 데이터를 전달할 때 countryDataCompleted_weatherDataCompleted 를 촉발할 수 있다는 것을 기억해야 한다.이것이 바로 우리가 Home Provider에서 만든 방법으로 UI를 변경하고 데이터를 업데이트하는 곳입니다.

    결론


    이러한 아키텍처를 사용하면 UI를 논리적으로 분리하는 데 성공했음을 알 수 있습니다.모든 것이 분리되어 코드를 쉽게 읽고 편집할 수 있다.

    소스 코드


    [ https://github.com/Marcusjnr/weather ]

    좋은 웹페이지 즐겨찾기