遭遇したケース
Fltterの実装では必要不可欠なBuildContext型のcontext
実態はWidgetと付随して作成されるWidgetの参照情報等を保持しているElementというオブジェクトのことです
そのcontext
を使用するメソッドを作成して、引数として渡そうとすると、以下の警告が出ました
Don't use 'BuildContext's across async gaps.
Try rewriting the code to not use the 'BuildContext', or guard the use with a 'mounted' check.
警告の内容
日本語訳
非同期ギャップで 'BuildContext' を使用しないでください。
'BuildContext' を使用しないようにコードを書き直すか、'mounted' チェックで使用を保護してください。
なるほど🤔
確かに警告が出ていた箇所は非同期処理を使っていました
非同期処理中の別スレッドの処理でcontext
の情報が書き替わる可能性がありますよね
すでにツリーから削除されているWidgetを使った処理が実行されることによるクラッシュやエラーを防ぐための警告だったんですね
解決策
ここで活躍するのがcontext.mounted
です!
警告文にもあるように、BuildContextが用意してくれているmouted
を使えば解決できます
mounted
とは対象のWidgetがツリーに存在しているか否かを示すbool値です
trueであればツリーに存在していることを表し、falseであれば既に使用されていない状態を表します
つまり、mounted
がfalseの場合にcontext
を使った処理を実行しないように実装すればよいということですね
今回の実装では、単純にifを使って修正しました
こんな感じで👇
void _closePage(BuildContext context) {
if (context.mounted) {
Navigator.pop(context); // 画面を閉じる
}
}
(画面を閉じるだけのメソッドになってますが実際にはもう少し処理があります)
if (!context.mounted) retuern;
で早期リターンを使っても良さそうですね
余談
mounted
は他にも不要な処理が実行されることを防ぐことで、メモリリーク防止やパフォーマンス向上目的でも使われることがあるみたいですね
ただ、警告の修正時にAIからは以下のアドバイスをいただきました
非同期処理を含むコンストラクターやプロパティは、非同期ファクトリメソッドやメソッドに変更することを検討してください
単に警告が出ないように修正するだけではなく、そもそも警告が出ないような設計を考えることが必要なのかも...