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

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

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

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Dart

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

Q&A

解決済

1回答

703閲覧

非同期処理をすると、エラー:LateInitializatioinError が解消できません。

hojo2021

総合スコア13

Flutter

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Dart

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

0グッド

0クリップ

投稿2022/11/05 15:38

Andoroid Studioで、Flutter(Dart)を用いて簡単なアプリを作っています。

サイトなどを参考にして、
画面遷移後、すでに前のページで作成済みのデータベースのテーブルからレコードを取得して、その値をTextに表示させたいのですが、表題の通り、LateInitializatioinErrorが出ます。

自分としては、「 late Map<String,dynamic>? gotMap;」の記述で初期化をしているつもりなのですが、何がいけないのでしょうか。

実現したいこと

すでに作成済みのデータベースのテーブルからレコードを取得してその値をTextに表示させたい。

発生している問題・エラーメッセージ

LateInitializationError: Field 'getedMap' has not been initialized.

該当のソースコード

表示させたいページ。initState()でメソッド呼び出しをしました。

class WorkingState extends StatefulWidget { final int? id; final int? time; const WorkingState({Key? key, required this.id, required this.time}) : super(key: key); @override State<WorkingState> createState() => _WorkingStateState(id,time); } class _WorkingStateState extends State<WorkingState>{ final int? _id; final int? _time; _WorkingStateState(this._id, this._time); late String todo; //これは初期化ではない? late Map<String,dynamic>? gotMap; @override void initState() { super.initState(); //メソッドの呼び出し getNogoMap(); todo = gotMap!["TODO"]; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('hello appbar!'), ), body: Center( child: Column( children: [ const Text("やること"), Text(todo?? ""), ], ), ), ); } //DbHelperを利用して、データベースからレコードをMapを取得しようとしています。 getNogoMap() async{ gotMap = await DbHelper.instance.getMap(_id); } }

DbHelperクラスのメソッド

//データベースからレコードを取得。レコードは1件なので、中身をMapにして返しています。 Future<Map<String, dynamic>> getNogoMap(int? id) async { final db = await database; List<Map<String,dynamic>> results = await db.query("NO_GO_RECORDS", where: "_id=?", whereArgs: [id]); Map<String, dynamic> map = results[0]; return map; }

試したこと

上記記述の変数の初期化のところで、
late Map<String,dynamic>? gotMap;
↑これを、↓のように変えて
late Future<Map<String,dynamic>>? gotMap;

さらに、メソッドの呼び出しのところで、
getNogoMap();
↑これを、↓のように変えて
gotMap = getNogoMap();

メソッドの方を、

Future<Map<String,dynamic>> getNogoMap() async{ Map<String,dynamic> map; map = await DbHelper.instance.getNogoMap(_id); return map; }

としますと、Mapから値を取り出すところで
下記エラーメッセージが出てコンパイルが通りません。

The operator '[]' isn't defined for the type 'Future<Map<String, dynamic>>'.

正直言って、非同期処理を行った場合の戻り値の型の意味が分かっていません。
そもそも Future型とはなんなのでしょうか?

また、本やサイトをみると、データベースから取得したListをクラスのリストにして戻しているようなのですが、そうしないとだめなのでしょうか。
もう、考えれば考えるほど分からなくなってきます。

どのようにしたら意図したとおりの動きをしてくれるのか、ご教示いただけたら幸いです。

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

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

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

下記のような質問は推奨されていません。

  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。

guest

回答1

1

ベストアンサー

LateInitializationErrorで出ているのはgetedMapです。
ただ、説明文等に出てくる名称はgotMapとなってます。なので途中で変数名を変更したソースコードだと仮定して記述します。

Flutterでは非同期処理を行った結果を使いWidgetを表示するにはFutureBuilderを使うのが一般的な解です。

ToDoを取得するためのFutureを作成し、それをFutureBuilderに渡しデータが確定したらそのデータでテキストを表示するというのが流でしょうか。

なおLateInitializationErrorが出たの以下の理由からです。

initStategetNogoMapを呼び出した時点ではまだgotMapは確定していません。
これはgetNogoMapがasyncな関数なので、この時点でgetNogoMap内の処理が走っていないからです。そのためgetNogoMapの下にあるtodo = gotMap!["TODO"];gotMapが確定していないというエラーになりました。

私はDartの非同期処理を次のように考えるようにしています。

  • asyncが付いている関数を呼び出すと、それは実行待機のキューに入れられる。
    この時点でasync内の処理は実行されない。
  • 現在実行している処理でawaitがあると、この時点までの状態で実行待機のキューに入れられる。
    この時点で実行している処理がないので、キューに入っている処理のうち実行可能なものを選び実行する。

で、この実行待機のキューに入れる単位がFutureといった感じです。
それを踏まえれば、LateInitializationErrorが発生した理由もなんとなく分かるのではないでしょうか。

以下の実装はFutureBuilderを使ったらこんな感じになるかなという例です。
実行していないので、エラー等あったら適宜修正してください。

dart

1class _WorkingStateState extends State<WorkingState> { 2 final int? _id; 3 final int? _time; 4 _WorkingStateState(this._id, this._time); 5 6 Future<String> getToDo() async { 7 final gotMap = await DbHelper.instance.getMap(_id); 8 return gotMap!["TODO"]; 9 } 10 11 late Future<String> future; 12 13 14 void initState() { 15 super.initState(); 16 future = getToDo(); 17 } 18 19 20 Widget build(BuildContext context) { 21 return Scaffold( 22 appBar: AppBar( 23 title: const Text('hello appbar!'), 24 ), 25 body: Center( 26 child: Column( 27 children: [ 28 const Text("やること"), 29 FutureBuilder<String>( 30 future: future, 31 builder: (context, snap) { 32 return Text(snap.data ?? ""); 33 }), 34 ], 35 ), 36 ), 37 ); 38 } 39}

投稿2022/11/06 01:29

ta.fu

総合スコア1573

hojo2021😍を押しています

下記のような回答は推奨されていません。

  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

また依頼した内容が修正された場合は、修正依頼を取り消すようにしましょう。

回答へのコメント

hojo2021

2022/11/06 07:19

ta.fu様、ご回答ありがとうございます! >途中で変数名を変更したソースコードだと仮定して記述します。 その通りです。質問をするにあたって修正しながらコピペしていったところ、 間違えたままの部分を残してしまっていました。わかりにくくさせてしまって申し訳なかったです。 載せていただいたコードで意図通りの表示をさせることができました! また、詳しい非同期処理に関するご説明もありがとうございます。 呼び出した、getNogoMap()の中にawaitがあるのでその後の処理も待ってくれているのかな、と勝手に思っていました。 Futureがどういったものなのかも、おぼろげながら分かってきました。 ただコードはまるっと、ta.fu様のコピペなので、これからFutureBuilderを調べると共に コードを読み解いて勉強していこうと思います。 この度は本当にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.69%

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

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

質問する

同じタグがついた質問を見る

Flutter

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Dart

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