フラッタにおけるレトロフィットとXMLの操作


フラッタにおけるレトロフィットとXMLの操作


まもなく、私はこの問題に対する答えを探していました.IOSの背景から来て、私は本当にレトロフィットやライブラリの他のコードジェネレータのようなライブラリにあまりにもされていない.

いずれにしても、それは私が探していた情報を見つけるのが少し難しかったです、そして、私がそれについてポストすることに決めた理由です.

何?


これはレトロフィットかDIOについてのポストではありません、私は簡潔に概念を説明します、しかし、このライブラリを説明しているかなり良いポストがすでにあります.
そうですか?
  • dio:それは非常にクールなものの間で、DARTのための非常に強力なHTTPクライアントです.
  • レトロフィット:ソースジェネレータを使用して、リクエストの型変換を行うことができます.
  • DIOとそのインターセプターについてもっと知りたいなら、私はthis postから見てみることをお勧めします.しかし、このポストに関しては、インターセプターがHTTPリクエストとあなたの結果の間に座る操作であることを覚えておく必要があるだけです.彼らは基本的に要求と応答を妨害するので、私たちはどんな操作も行うことができます.

    私たちは何をしていますか。


    我々は、我々は停止7602に到着する次のバスを取得するSmart Dublin 🇮🇪APIに当っている小さなサンプルアプリケーションを構築します.実際の製品では、我々は任意の停止をクエリすることができますので、我々のアプリケーションを構築するが、我々のサンプルについては、この停止番号の情報を取得します.

    これは、私たちがフェッチするエンドポイントです.
    あなたは、ポストの最後に完全なプロジェクトを見つけるが、あなたが沿って続くようにしたい場合は、新しいフラッターアプリを作成することによって起動します.

    ヒア プロジェクト構造


    まず、ファイル構造を作成します.ダート到着.ダートとSmartRangeダブリン.スクリーンショットのようにダーツファイル.

    プロジェクトの構成

    依存


    いくつかの依存関係やdevdepend依存関係を追加する必要がありますが、一般的な行では以下のようになります:
  • レトロフィット
  • XML
  • XML 2 JSON
  • ビルドランナーランナー
  • 次のように依存関係を追加します.
    dependencies:
      flutter:
        sdk: flutter
      cupertino_icons: ^0.1.3
      retrofit: ^1.3.4
      xml: ^3.5.0
      xml2json: ^4.2.0
    
    dev_dependencies:
      flutter_test:
        sdk: flutter
      retrofit_generator: ^1.3.7
      build_runner: ^1.10.0
    
    念のため、これを書いた時点で、フラッタ1.21.0 - 10.0を使用しています.プレ18とダーツ2.10 .

    我々の最初のレトロフィットネットワーク要求


    SmartSumダブリンを開けて始めよう.我々のレトロフィットスケルトンを書き留めて、書いてください:
    *import *'package:retrofit_xml_sample_app/models/stop.dart';
    *import *'package:dio/dio.dart';
    *import *'package:retrofit/retrofit.dart';
    
    *part *'smart_dublin.g.dart';
    
    @RestApi(baseUrl: "https://data.smartdublin.ie/cgi-bin/rtpi/")
    *abstract class *SmartDublinClient {
      *factory *SmartDublinClient(Dio dio, {String baseUrl}) {
        *return *_SmartDublinClient(dio, baseUrl: baseUrl);
      }
    
      @GET("/realtimebusinformation?format=xml")
      @DioResponseType(ResponseType.plain)
      Future<Stop> getStopInformation(@Query("stopid") String stopId);
    }
    
    上のコードではいくつかのことが起こります.
  • 私たちは、一部のSmartSumダブリンとそれの別の部分があるファイルを教えている.G .ダーツ'.この他の部分はBuildRankランナーによって自動生成されます.彼らはすべてのエンドとしてファイルを生成することができるようになります.Gダーツ.
  • @ restapi @ @ get & @ dioresponseTypeなどの注釈を使用しています.この注釈には、ファイルの2番目の部分を生成するためにレトロフィットに使用される情報が含まれます.
  • と我々はXML形式を取得するために要求している!😱 まあ、その部分も私の欠点です.XMLを返すような単純なサンプルを思い出せませんでした.真実は、現在の終点のほとんどがJSONを返す機会があるということです;しかし、これはレガシーシステムや時代遅れのAPIでは正しくありません.私はこの単純なAPIのXML上での戻りを強制的に説明の目的のためだけに決定した.
  • そして、あなたがそれについて疑問に思っているならば、あなたは前に最も注釈された注釈を持っています、例えば、@ overrideについて考えてください.
    いずれにせよ、このように見えるレトロフィットを使用する方法に関する多くの例があります.また、インターセプターと呼ばれるものの使用を見つけるでしょう.我々がポストの冒頭で言及したように、インターセプターは我々が彼らにどんな操作も行うことができるように、要求と応答を捕えます.
    インターセプターで何かできることは、デバッグモードになっている間にコンソールで全てのレスポンスを出力することです(ネットワーク操作をすばやくデバッグするのに非常に便利です).このような場合は、リターン文の右側にある工場本体に以下を追加する必要があります.
    dio.interceptors.add(LogInterceptor(requestBody: *true*, responseBody: *true*));
    
    インターセプターは特に私たちのユースケースで興味深いです.なぜなら、XMLを返すネットワークリクエストを実行しているときには、応答を傍受し、JSONファイルに変換して動作させることができます.次のインターセプターでこれを行うことができます.
    dio.interceptors.add(InterceptorsWrapper(
      onResponse: (Response response) *async *{
        response.data = Utils.*decodeXmlResponseIntoJson*(response.data);
        *return *response;
      },
    ));
    
    ここに追加の手順があり、utilsファイルを作成したのですが、utils/mainを作成するためには、utilsファイルを作成しました.dartファイルをペーストします.
    *import *'dart:convert';
    *import *'package:xml2json/xml2json.dart';
    
    *const *kQuoteReplacer = "¿*¿*¿*¿*";
    
    *class *Utils {
      *static dynamic decodeXmlResponseIntoJson*(String data) {
        String cleanDataString = data.replaceAll("&quot;", kQuoteReplacer);
        *final *Xml2Json transformer = Xml2Json();
        transformer.parse(cleanDataString);
        *final *json = transformer.toGData();
        *return *jsonDecode(json);
      }
    }
    
    Xml 2 JSONライブラリから別のJSONトランスフォーマーを使用できます.私はgdataをより良いこの変換のための私に合うものを見つけたが、それはあなたのユースケースの場合ではない可能性がありますので、いくつかの他の変圧器を確認してください.

    モデル


    私たちのレトロフィットコードがSTOPと呼ばれるモデルを使用していることに気づいたかもしれません.これは私たちのネットワークのリクエストの応答をすぐに我々の停止モデル、かなり便利なオブジェクトに変換されているためです!
    このモデルは、「Fromjson」メソッドをレトロフィットで動作するようにするだけです.
    ストップモデルをストップにコピーしましょう.ダート
    *import *'package:retrofit_xml_sample_app/models/arrival.dart';
    
    *class *Stop {
      *final *List<Arrival> arrivals;
      *final *String stopId;
    
      Stop({
        *this*.arrivals = *const *[],
        *this*.stopId,
      });
    
      *factory *Stop.fromJson(Map<String, *dynamic*> jsonMap) {
        *final *stopId = jsonMap['realtimeinformation']['stopid']['\$t'];
        *final *List<Arrival> arrivalsList = [];
        *final *results = jsonMap['realtimeinformation']['results']['result'];
    
        *if *(results != *null*) {
          *for *(*var *result *in *results) {
            arrivalsList.add(Arrival.fromJson(result));
          }
        }
    
        *return *Stop(
          arrivals: arrivalsList,
          stopId: stopId,
        );
      }
    
      @override
      String toString() {
        *return *'Stop { stopId: $stopId, arrivals: ${arrivals.length} }';
      }
    }
    
    ファクトリメソッドは、レスポンスから値を持つオブジェクトを充填する担当者です.これは基本的にモデルへの応答を解析します.
    私がこの例のクラスをモデル化した方法は、ストップが到着のリストを持っているということです.到着モデルのコードは次のようになります.
    *class *Arrival {
      *final *String route;
      *final *String origin;
      *final *String destination;
      *final *String dueTime;
    
      Arrival({
        *this*.route,
        *this*.origin,
        *this*.destination,
        *this*.dueTime,
      });
    
      *factory *Arrival.fromJson(Map<String, *dynamic*> jsonMap) {
        *final *route = jsonMap['route']['\$t'];
        *final *origin = jsonMap['origin']['\$t'];
        *final *destination = jsonMap['destination']['\$t'];
        *final *dueTime = jsonMap['duetime']['\$t'];
    
        *return *Arrival(
          route: route,
          origin: origin,
          destination: destination,
          dueTime: dueTime,
        );
      }
    
      @override
      String toString() {
        *return *'Arrival { route: $route }';
      }
    }
    

    自動生成


    今、我々は、我々が以前に見たG . Dartファイルを自動生成することができます.
    そのためには、プロジェクトフォルダ内の端末でこれを実行してください.
    flutter pub run build_runner build
    
    そうした後に、新しい自動生成されたファイルSmartSumダブリンを見るべきです.G . DARTによる手法の実装

    このファイルを既に実行していて、以前に自動生成されたファイルを上書きする必要がある場合は、build - rangerコマンドに- delete -競合する出力フラグを追加することができます.
    flutter pub run build_runner build --delete-conflicting-outputs
    

    すべてをまとめる


    私たちの新しいレトロフィット方法を実際に使う時です.最初にUIをビルドする必要があります.ちょうどこれを維持するために、私はメインで一緒にすべてのUIを結びました.ダートファイル.
    MyAppのステイタスウィジェットが必要になります.
    *import *'package:flutter/material.dart';
    *import *'package:retrofit_xml_sample_app/api/smart_dublin.dart';
    *import *'package:retrofit_xml_sample_app/models/stop.dart';
    *import *'package:dio/dio.dart';
    
    *const *kStopId = '7602';
    
    *void *main() {
      runApp(MyApp());
    }
    
    *class *MyApp *extends *StatelessWidget {
      @override
      Widget build(BuildContext context) {
        *return *MaterialApp(
          title: 'Bus stop info',
          theme: ThemeData(
            primarySwatch: Colors.*blue*,
            visualDensity: VisualDensity.*adaptivePlatformDensity*,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    *class *MyHomePage *extends *StatefulWidget {
      MyHomePage({Key key}) : *super*(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    *class *_MyHomePageState *extends *State<MyHomePage> {
       //To complete next
    }
    
    次に、我々はCount MyHomePageStatesクラスを満たします.最初に我々の変数、停止を保持する1つ、別の1つは、新しいAPIクライアントを保持します.
    Stop _stop = Stop(arrivals: [], stopId: kStopId);
    *final *_apiClient = SmartDublinClient(Dio());
    
    私たちは、停止モデルのための到着の空のリストをデフォルト値として使用しています.
    SmartDubleClientクラスのinitメソッドは、新しいdioインスタンスを送信する必要があります.何らかの理由で複数のAPIクライアントを使用している場合は、同じDIOインスタンスを再利用することができます(少なくともこの時点では実際には副作用が発生しません).
    我々のAPIクライアントからSTOP情報を要求する新しいメソッドを作成し、このサンプルの状態管理ソリューションとして状態を使用します.
    *void *loadStopInformation() *async *{
      Stop stop = *await *_apiClient.getStopInformation(kStopId);
      setState(() {
        _stop = stop;
      });
    }
    
    とinitstateとbuildのメソッドをオーバーライドします.
    @override
    *void *initState() {
      *super*.initState();
      loadStopInformation();
    }
    
    @override
    Widget build(BuildContext context) {
      *return *Scaffold(
        body: SafeArea(
          child: Column(
            children: <Widget>[
              Padding(
                padding: *const *EdgeInsets.all(16.0),
                child: Text(
                  ' 🚌 Stop 7602',
                  style: TextStyle(
                    fontWeight: FontWeight.*bold*,
                    fontSize: 32,
                  ),
                ),
              ),
              Flexible(
                child: buildList(),
              )
            ],
          ),
        ),
      );
    }
    
    ビルドメソッド内でBuildListを呼び出していることに気づいたかもしれません.私は、サンプルで明快さのために彼らを分離させました:
    Widget buildList() {
      *if *(_stop.arrivals.isEmpty) {
        *return *Text("Sorry, there are no buses anytime soon 🤷🏽‍♀️");
      }
      *return *ListView.builder(
        itemCount: _stop.arrivals.length,
        itemBuilder: (BuildContext context, int index) {
          *return *Padding(
            padding: *const *EdgeInsets.fromLTRB(16, 8, 16, 8),
            child: Container(
              height: 40,
              decoration: BoxDecoration(
                color: Colors.*white*,
                borderRadius: BorderRadius.circular(10),
                boxShadow: [
                  BoxShadow(
                    color: Colors.*grey*,
                    spreadRadius: 1,
                    offset: Offset(0, 0),
                  )
                ],
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Text("Arriving in ${_stop.arrivals[index].dueTime} mins"),
                  Text(
                      "${_stop.arrivals[index].route} to ${_stop.arrivals[index].destination}"),
                ],
              ),
            ),
          );
        },
      );
    }
    
    ビルドリストメソッドでは、停止の到着が空で、リストがない場合にメッセージを表示します.
    一緒にすべてを置いた後、あなたはこのようなものを見るべきです👇🏼

    アプリの最終キャプチャ

    おめでとう!🥳


    あなたがそれを通して作ったうれしい!あなたがポストを楽しんで、道で何かを学ぶという望み.
    あなたがちょうどコードにまっすぐに飛び込みたいならば、あなたはそれをここで見つけます👇🏼

    私はあなたの考えを知っているし、次に聞いてみたいもの!次のポストを参照してください!👋