DartとFlutterで先物とストリームを開始する方法
序章
多くの場合、アプリケーションは外部APIおよびデータベースと対話する機能を必要とします。 これに伴い、特定の要求と操作が完了するのを待っている間に、記述された方法とは異なる順序で実行されるコードを処理するという問題が発生します。
この記事では、 Dart 、特にFlutterが非同期リクエストでどのように機能するかを探ります。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Flutterをダウンロードしてインストールするには。
- Android StudioまたはVisual StudioCodeをダウンロードしてインストールするには。
- コードエディタ用のプラグインをインストールすることをお勧めします。
AndroidStudio用にインストールされたFlutterおよびDartプラグイン。 VisualStudioCode用にインストールされたFlutter拡張機能。
このチュートリアルは、Flutter v2.0.6、Android SDK v31.0.2、およびAndroidStudiov4.1で検証されました。
非同期コードを理解する
同期コードでは、外部APIに情報のリクエストを送信すると、応答が得られるまでに時間がかかります。 私たちのマシンはそれが完了するのを待って、最初の要求とは関係がないかもしれないことを停止します。 問題は、何かが時間がかかるたびにスクリプトの実行を停止したくないことですが、戻りデータに依存するものを時期尚早に実行したくないため、要求が成功したにもかかわらずエラーが発生する可能性があります。
両方の長所は、リクエストが返されるのを待っている間、そのリクエストに依存するコードが利用可能になったときにのみ実行できるように、マシンが先に進むようにロジックを設定することです。
私たちのアプリのデータは、それらがすでに利用可能であるかどうか、およびそれらが特異であるかどうかに応じて、4つの形式のいずれかになります。
この例では、先物とストリームについて説明します。
プロジェクトの設定
Flutter用に環境を設定したら、次のコマンドを実行して新しいアプリケーションを作成できます。
- flutter create flutter_futures_example
新しいプロジェクトディレクトリに移動します。
- cd flutter_futures_example
flutter create
を使用すると、ボタンがクリックされた回数を表示するデモアプリケーションが作成されます。
この例の一部は、 REST CountriesAPIに依存しています。 国名を指定すると、このAPIは国に関する情報を返します。 たとえば、Canada
のリクエストは次のとおりです。
https://restcountries.eu/rest/v2/name/Canada
これには、httpパッケージも必要です。
コードエディタでpubspec.yaml
を開き、次のプラグインを追加します。
dependencies:
flutter:
sdk: flutter
http: 0.13.3
次に、コードエディタでmain.dart
を開き、次のコード行を変更して、 GetCountryボタンを表示します。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
void getCountry() {}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
onPressed: () => getCountry(),
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(15),
child: Text('Get Country', style: TextStyle(color: Colors.white))
),
),
),
);
}
}
この時点で、http
パッケージを使用した新しいFlutterプロジェクトができました。
then
およびcatchError
を使用する
try…catchinJavaScript と非常によく似ており、Dartを使用するとメソッドをチェーン化できるため、戻りデータを次のデータに簡単に渡すことができ、Futuresと呼ばれるPromiseのようなデータ型も返すことができます。 先物は、文字列などの特異なタイプのデータであり、後で利用できるようになります。
この手法を使用するには、操作を実行してから、返されたデータをパラメーターとして渡して.then
をチェーンし、必要に応じて使用します。 その時点で、追加の.then
をチェーンし続けることができます。 エラー処理の場合は、最後に.catchError
を使用して、渡されたものをすべてスローします。
コードエディタでmain.dart
に戻り、.then
と.catchError
を使用します。 まず、void GetCountry() {}
をFuture GetCountry(country)
に置き換えます。 次に、国名をonPressed: () => GetCountry()
に追加します。
// ...
class MyHomePage extends StatelessWidget {
Future getCountry(country) {
Uri countryUrl = Uri.http('restcountries.eu', '/rest/v2/name/$country');
http
.get(countryUrl)
.then((response) => jsonDecode(response.body)[0]['name'])
.then((decoded) => print(decoded))
.catchError((error) => throw(error));
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
onPressed: () => getCountry('Canada'),
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(15),
child: Text('Get Country', style: TextStyle(color: Colors.white))
),
),
),
);
}
}
変更を保存し、シミュレーターでアプリケーションを実行します。 次に、国を取得ボタンをクリックします。 コンソールは国の名前を記録します。
async
およびawait
を使用する
多くの人が読みやすいと思う代替構文はAsync/Awaitです。
Async / Awaitは、JavaScript とまったく同じで動作します。関数名の後にasync
キーワードを使用し、実行に時間がかかるものの前にawait
キーワードを追加します。 getリクエストのように。
コードエディタでmain.dart
に戻り、async
とawait
を使用します。 これで、値が返されたときに、それ以降のすべてが実行されます。 エラー処理の場合、try/catchブロックでエラーをスローできます。
// ...
class MyHomePage extends StatelessWidget {
Future getCountry(country) async {
Uri countryUrl = Uri.http('restcountries.eu', '/rest/v2/name/$country');
try {
http.Response response = await http.get(countryUrl);
Object decoded = jsonDecode(response.body)[0]['name'];
print(decoded);
} catch (e) { throw(e); }
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
onPressed: () => getCountry('Canada'),
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(15),
child: Text('Get Country', style: TextStyle(color: Colors.white))
),
),
),
);
}
}
変更を保存し、シミュレーターでアプリケーションを実行します。 次に、国を取得ボタンをクリックします。 コンソールは国の名前を記録します。
ストリームの使用
Dartの特別な点は、非同期でロードされる多くの値がある場合にStreamsを使用することです。 GETリクエストのように一度接続を開く代わりに、接続を開いたままにして新しいデータの準備をすることができます。
この例では、 Firebase やGraphQLを使用するなど、Streamsを許可するバックエンドを設定すると少し複雑になるため、新しい「メッセージ」を発行してチャットアプリケーションデータベースの変更をシミュレートします。一秒ごと。
StreamController
クラスを使用してストリームを作成できます。これは、先物のリストのように動作するため、List
と同様に機能します。
listen
やclose
などのstream
のプロパティを使用してストリームを制御し、ストリームを開始および停止できます。
警告:ウィジェットを削除するときは、常にclose()
を使用することが重要です。 ストリームは、シャットオフされるまで継続的に実行され、元のウィジェットがなくなった場合でもコンピューティング能力を消費します。
次に、コードエディタでmain.dart
を開き、次のコード行を置き換えてdart:async
をインポートし、StatefulWidget
を使用します。
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
StreamController<String> streamController = StreamController();
void newMessage(int number, String message) {
final duration = Duration(seconds: number);
Timer.periodic(duration, (Timer t) => streamController.add(message));
}
void initState() {
super.initState();
streamController.stream.listen((messages) => print(messages));
newMessage(1, 'You got a message!');
}
void dispose() {
streamController.close();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
padding: EdgeInsets.all(15),
child: Text('Streams Example'),
),
),
);
}
}
このコードは、コンソールにYou got a message
を継続的に出力します。
標準ストリームは、一度に1人のリスナーしか許可しないという点で少し制限される可能性があります。 代わりに、StreamController
クラスのbroadcast
プロパティを使用して、複数のチャネルを開くことができます。
// ...
StreamController<String> streamController = StreamController.broadcast();
// ...
void initState() {
super.initState();
streamController.stream.listen((messages) => print('$messages - First'));
streamController.stream.listen((messages) => print('$messages - Second'));
newMessage(1, 'You got a message!');
}
// ...
このコードは、コンソールにYou got a message - First
とYou got a message - Second
を継続的に出力します。
結論
この記事では、Dart、特にFlutterが非同期リクエストでどのように機能するかを探りました。 Dartの非同期プログラミングにより、インテリジェントで動的なアプリの開発を開始できます。
Flutterについて詳しく知りたい場合は、Flutterトピックページで演習とプログラミングプロジェクトを確認してください。