質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

解決済

1回答

1312閲覧

アプリを最初に開いたとき、initStateを待って描画させたい

hikagami

総合スコア14

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2022/09/19 01:38

実現したいこと

タイトルの通り、アプリを最初に開いたとき、initState内のデータベースの取得を待って描画させたいです。
現状だとデータベースの値が反映される前にwidgetが生成(?)されてしまって、

createsteatが実行されたあとinitStateが実行されているのでそれが原因かなと思っているのですが解決策が浮かばず...
よろしくお願いします。

class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override void initState() { Future.delayed(Duration.zero).then((_) async {                                     〜〜省略〜〜

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

一般的にFuture(もしくはasync関数)での結果をウィジェットの内容として使うのであれば、FutureBuilderを使う(推奨方法)か表示用のデータが集まった後にsetStateを呼び出すかのどちらかです。

以下はFutureBuilderのAPIヘルプのリンクです。
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

このサンプルを見れば分かるんじゃないでしょうか。

上のコードでは実装されている関数だけで動作順序を見ると、以下の様になるんじゃないでしょうか。
多分Future内の関数はbuildでウィジェット作成の後に呼び出される感じです。

  1. 番号リストcreateStateで_MyHomePageStateのインスタンスを作成
  2. initStateが呼び出されFutureの実行が予約される
  3. buildでウィジェットの作成をする
  4. Futureに登録されている関数が実行される

initState内かbuildでウィジェット作成前に、initStateで呼び出したFutureをawaitすればFuture内の関数の処理完了後ウィジェットの作成を行うこともできますが、これはFutureの処理時間が一瞬である前提であれば良いですが、処理時間が長期に及ぶ場合、そこで処理がいったん止まるので、いい対策とは言えないです。
initState内でawaitする件については、initStateがもともとasyncな関数ではなく、上位側からawaitされていないので、対応として問題があるので記述として削除しました。


initState内のFuture関数内でsetStateする処理のサンプルです。

dart

1class ListTile2 extends StatefulWidget { 2 const ListTile2({Key? key}) : super(key: key); 3 4 5 State<ListTile2> createState() => _ListTile2State(); 6} 7 8class _ListTile2State extends State<ListTile2> { 9 10 void initState() { 11 super.initState(); 12 Future(() async { 13 await Future.delayed(const Duration(seconds: 1)); 14 value = "hoge"; 15 setState(() {}); 16 }); 17 } 18 19 String value = "10"; // これが表示用のデータで初期値10でFuture内でhogeに変更している。 20 21 22 Widget build(BuildContext context) { 23 return Scaffold( 24 appBar: AppBar( 25 title: const Text("ListTile2 test"), 26 ), 27 body: Card( 28 child: ListTile( 29 title: Row( 30 mainAxisAlignment: MainAxisAlignment.spaceBetween, 31 children: [Text(value), const Text("10")], 32 ), 33 trailing: const Icon(Icons.arrow_forward_ios), 34 ), 35 ), 36 ); 37 } 38}

投稿2022/09/19 03:39

編集2022/09/19 08:24
ta.fu

総合スコア1740

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hikagami

2022/09/19 05:14

回答ありがとうございます。 >> initState内かbuildでウィジェット作成前に、initStateで呼び出したFutureをawaitすればFuture内の関数の処理完了後ウィジェットの作成を行うこともできますが 待ち時間は一瞬であるし、initState内で複数のsetStateを行いたいのでこちらの方法を取らせてもらおうかと思っています。しかし自分でいじってみたもののやり方が分からず... ``` void initState(){ super.initState(); Future(()async{ WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); final ref = FirebaseDatabase.instance.ref(); final ~~~ = await ref.child(~~~).get(); final ~~~ = await ref.child(~~~).get(); final ~~~ = await ref.child(~~~).get(); setState(() { ~~~省略~~~ } ); } ); } ``` 現在このような感じなのですが、どう変えればFutureをawaitをAwaitさせられるのでしょうか。
ta.fu

2022/09/19 08:29

一部出来ないことを書いてしまったので回答修正しました。 あとinitState内のFutureでsetStateするサンプルコードを追加しておきました。 なお、コメント提示されたコードの場合、DBから取り出したデータはあくまでFuture内の関数内でのみ完結しているような実装と見受けられます。 await ref.childで取り出したデータをクラスメンバーの変数に代入しそれをウィジェットで表示するような実装にしないとだめだと思います。 それともsetState内の省略と書かれた部分でそれをやっているのでしょうか。 呈示されたコードでは不明な部分が多すぎるので回答はできないです。
hikagami

2022/09/19 10:36

返答ありがとうございます。 提示していただいたコードですが、実行すると"10"が1秒ほど表示されると思うのですが、本質問は10(初期値)を表示せずに最初からfogeという値を入れたいというものです。 言葉足らずで申し訳有りません。 コードも変な省略をしてしまいましたが、提示していただいたコードと全く同じ処理です。
ta.fu

2022/09/19 11:23

呈示したコードでは初期値10としましたが、それを空白にしておけば、ユーザーの見た目では初期値としてDBから取得したデータを表示したととらえることもできるのですが、そういう考え方はとれませんか? 今回待機時間を1秒としましたが、例えばDB取得に10ms以内とかであればユーザーに認知はできないと思います。 あと本当に初めから表示させたいのであれば、MyHomePageを呼び出す側で値を確定しておき、パラメータなどでその値を渡すという方法しかないと思います。 一つの方法としては、Future関数をawaitで完了待ちした後にNavigatorでMyHomePageにページに遷移するという感じでしょうか。 関連知識の習得等考えると、先は長いと思います。(しかしよく使う考え方なので覚えて損はないですが。)
hikagami

2022/09/19 15:24

ありがとうございます。 そうですね、そもそもの知識量が全く足りていないので精進したいと思います... 今回はお付き合いいただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問