こんにちは、CX事業本部 IoT事業部の若槻です。
最近はじめたFlutterアプリ開発で、画面(Widget)の初回表示時にのみ任意の処理を実行したいケースがあったので、対応した内容を紹介します。
導入
サンプルとして、flutter create
下記は生成されたmain.dart
で定義されたMyHomePage
画面のコードです。(自動挿入されるコメントは省いています。)
lib/main.dart
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
Flutter(Dart)で画面(Widget)を実装する場合は、主にStatefulWidgetまたはStatelessWidgetを使用します。
- StatefulWidget class - widgets library - Dart API
- StatelessWidget class - widgets library - Dart API
それぞれの使い分けは名前の通りで、StatefulWidgetは状態(State)を持たせたいWidget、StatelessWidgetは静的なWidgetを作る際に使用します。
今回のサンプルのカウンターアプリではボタンクリックによるカウントアップを画面表示させるため、上記コードの通りStatefulWidgetが使われています。
initStateを使って初回のみ実行させる
さてこのStatefulWidgetの画面の初回表示時に任意の処理を実行したいです。
その場合はStatefulWidgetで利用可能なメソッドinitStateを使います。
_MyHomePageState
で次のようにinitState
で処理を記載します。
lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
void initState() {
print("MyHomePage画面が表示されました。");
super.initState();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
//略
}
}
StatefulWidgetではStateオブジェクトによるライフサイクル管理が行われ、initState
はWidgetの初期化時のみ呼び出されます。
flutter run -d chrome
コマンドでアプリをWebで起動します。
するとPrint出力処理が行われました。
$ flutter run -d chrome
Launching lib/main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome... 10.8s
This app is linked to the debug service: ws://127.0.0.1:58290/bXekE9NwhZU=/ws
Debug service listening on ws://127.0.0.1:58290/bXekE9NwhZU=/ws
Running with sound null safety
To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".
An Observatory debugger and profiler on Chrome is available at: http://127.0.0.1:58290/bXekE9NwhZU=
Flutter Web Bootstrap: Programmatic
MyHomePage画面が表示されました。
The Flutter DevTools debugger and profiler on Chrome is available at: http://127.0.0.1:9102?uri=http://127.0.0.1:58290/bXekE9NwhZU=
ボタンをクリックしてカウンターを増やしてみます。
コンソールには追加のPrint出力は表示されていません。ちゃんと初回画面表示時のみ処理を実行できています!
誤った方法
次のようにWidget build()
内に記載した処理はステート変更毎に実行されるため、画面初回表示時のみ実行したい場合は誤った方法となります。
lib/main.dart
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
print('MyHomePage画面が表示されました。');
//略
}
}
flutter run -d chrome
コマンドでアプリを起動し、ボタンクリックしてカウントアップを行います。
すると画面初回表示時に加えてボタンクリック毎に処理が実行されてしまいました。
$ flutter run -d chrome
Launching lib/main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome... 10.5s
This app is linked to the debug service: ws://127.0.0.1:58600/9so_Ka2lQ9w=/ws
Debug service listening on ws://127.0.0.1:58600/9so_Ka2lQ9w=/ws
Running with sound null safety
To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".
An Observatory debugger and profiler on Chrome is available at: http://127.0.0.1:58600/9so_Ka2lQ9w=
Flutter Web Bootstrap: Programmatic
MyHomePage画面が表示されました。
The Flutter DevTools debugger and profiler on Chrome is available at: http://127.0.0.1:9102?uri=http://127.0.0.1:58600/9so_Ka2lQ9w=
MyHomePage画面が表示されました。
MyHomePage画面が表示されました。
MyHomePage画面が表示されました。
MyHomePage画面が表示されました。
MyHomePage画面が表示されました。
Flutterのライフサイクルの概念をよく分かっていない頃によくこれをやらかしました。
以上