Flutter(Flutter 3.3.2/Dart 2.18.1)にてBottomNavigationBarを使ったページの作成をしています。
BottomNavigationBarのアイテムリスト(LIST<BottomNavigationBarItem>)をデータベースから取得し表示したいのですが、データ取得が非同期処理の為、先にWidgetの生成が始まりその時点ではアイテムリストが空となり「_AssertionError ('package:flutter/src/material/bottom_navigation_bar.dart': Failed assertion: line 197 pos 15: 'items.length >= 2': is not true.)」といったエラーメッセージが表示されます。
エラーの意味する事は理解でき、データベースからの情報の取得が非同期処理の為、その処理完了後に「Widget build」が実施されれば良いとは思うのですが、どうやって解決すれば良いのかわかりません。
どのようにすれば「reloadTabs()」により非同期処理の実行完了後に取得した情報で「Widget build」を実行できるのでしょうか。
該当のソースコード
dart
1import 'dart:io'; 2import 'package:flutter/material.dart'; 3import 'package:sqflite/sqflite.dart'; 4import 'package:path/path.dart'; 5import 'package:path_provider/path_provider.dart'; 6 7void main() { 8 9 runApp( 10 MaterialApp( 11 debugShowCheckedModeBanner: false, 12 initialRoute: '/', 13 routes: { 14 '/': (context) => const MyApp(), 15 }, 16 ), 17 ); 18 19} 20 21class MyApp extends StatefulWidget { 22 23 const MyApp({Key? key}) : super(key: key); 24 25 26 State<MyApp> createState() => MyAppState(); 27 28} 29 30class MyAppState extends State<MyApp> { 31 32 int screenIndex = 0; 33 34 final List<Widget> pages = [ 35 const FirstPage(), 36 const SecondPage() 37 ]; 38 39 40 Widget build(BuildContext context) { 41 42 return Scaffold( 43 body: pages[screenIndex], 44 bottomNavigationBar: BottomNavigationBarPage( 45 changeTab: (int index) { 46 changeTab(index); 47 } 48 ) 49 ); 50 51 } 52 53 void changeTab(int tabIndex) { 54 55 setState(() { 56 screenIndex = tabIndex; 57 }); 58 59 } 60 61} 62 63class FirstPage extends StatefulWidget { 64 65 const FirstPage({Key? key}) : super(key: key); 66 67 68 FirstPageState createState() => FirstPageState(); 69 70} 71 72class FirstPageState extends State<FirstPage> { 73 74 75 Widget build(BuildContext context) { 76 77 return Scaffold( 78 79 body: Center( 80 child: Column( 81 mainAxisAlignment: MainAxisAlignment.center, 82 children: const <Widget>[ 83 Text( 84 '1ST Page', 85 ), 86 ], 87 ), 88 ), 89 90 ); 91 92 } 93 94} 95 96class SecondPage extends StatefulWidget { 97 98 const SecondPage({Key? key}) : super(key: key); 99 100 101 SecondPageState createState() => SecondPageState(); 102 103} 104 105class SecondPageState extends State<SecondPage> { 106 107 108 Widget build(BuildContext context) { 109 110 return Scaffold( 111 112 body: Center( 113 child: Column( 114 mainAxisAlignment: MainAxisAlignment.center, 115 children: const <Widget>[ 116 Text( 117 '2ND Page', 118 ), 119 ], 120 ), 121 ), 122 123 ); 124 125 } 126 127} 128 129class BottomNavigationBarPage extends StatefulWidget { 130 131 const BottomNavigationBarPage({Key? key, required this.changeTab}) : super(key: key); 132 133 final Function(int) changeTab; 134 135 136 BottomNavigationBarPageState createState() => BottomNavigationBarPageState(); 137 138} 139 140class BottomNavigationBarPageState extends State<BottomNavigationBarPage> { 141 142 int tabIndex = 0; 143 144 List<BottomNavigationBarItem> bottomItems = []; 145 146 147 void initState() { 148 149 super.initState(); 150 151 reloadTabs(); 152 153 } 154 155 156 Widget build(BuildContext context) { 157 158 return BottomNavigationBar( 159 items: bottomItems, 160 currentIndex: tabIndex, 161 onTap: (index) { 162 163 setState(() { 164 tabIndex = index; 165 }); 166 167 widget.changeTab(index); 168 169 }, 170 ); 171 172 } 173 174 void reloadTabs() async { 175 176 final items = await DatabaseHelper.getTabs(); 177 178 List<BottomNavigationBarItem> tabItems = []; 179 180 for (var item in items) { 181 182 tabItems.add( 183 BottomNavigationBarItem( 184 icon: const Icon(Icons.square), 185 label: item["name"], 186 ) 187 ); 188 189 } 190 191 setState(() { 192 bottomItems = tabItems; 193 }); 194 195 } 196 197} 198 199class DatabaseHelper { 200 201 static Future<List<Map<String, dynamic>>> getTabs() async { 202 203 final db = await DatabaseHelper.db(); 204 205 final rows = await db.rawQuery(""" 206 SELECT 207 tabs.id, 208 tabs.name 209 FROM 210 tabs 211 """ 212 ); 213 214 return rows; 215 216 } 217 218 static Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async { 219 220 await db.transaction((txn) async { 221 222 if(oldVersion == 0){ 223 224 await txn.execute(""" 225 CREATE TABLE "tabs" ( 226 "id" INTEGER, 227 "name" TEXT NOT NULL, 228 PRIMARY KEY("id" AUTOINCREMENT) 229 ); 230 """); 231 232 await txn.execute(""" 233 INSERT INTO tabs(name) 234 VALUES("1ST") 235 """); 236 237 await txn.execute(""" 238 INSERT INTO tabs(name) 239 VALUES("2ND") 240 """); 241 242 } 243 244 }); 245 246 } 247 248 static Future<Database> db() async { 249 250 final dbFilePath = await getDbPath(); 251 252 debugPrint(dbFilePath); 253 254 return openDatabase( 255 dbFilePath, 256 version: 3, 257 onUpgrade: _onUpgrade, 258 ); 259 260 } 261 262 static Future<String> getDbPath() async { 263 264 var dbFilePath = ''; 265 266 if (Platform.isAndroid) { 267 dbFilePath = await getDatabasesPath(); 268 } else if (Platform.isIOS) { 269 final dbDirectory = await getLibraryDirectory(); 270 dbFilePath = dbDirectory.path; 271 } 272 273 final path = join(dbFilePath, 'app.db'); 274 275 return path; 276 277 } 278 279}
なお、動作の為に以下のパッケージを導入しております。
pubspec.yaml
1sqflite: ^2.0.3+1 2path: ^1.8.2 3path_provider: ^2.0.11
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/09/21 01:12