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

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

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

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

Q&A

0回答

294閲覧

ChangeNotifierを使ったリストの更新方法

退会済みユーザー

退会済みユーザー

総合スコア0

Flutter

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

0グッド

0クリップ

投稿2023/03/01 15:42

実現したいこと

●あるページから別ページのリストビューを自動的に更新したいです

●本サイトにて以前にも似たような質問をして回答を頂いていますが
階層が深く(複数のクラス/ウィジェットを経由)すると対応が難しい事がわかりましたのでProviderを使う事にしました。

前提

●メインページにBottomAppBar等を使用したアプリを作っています
→アプリ起動後の初期画面はPage1を表示
→Page1のデータ取得にはData2Notifierを使用

●BottomAppBarの中央にくるIconButtonからページ2に移動します
→Page2はDBにデータを登録する処理
→Page1はDBに登録されたデータを取得してリストに表示する処理

発生している問題

● notifyListenersでデータを送信し、Consumerで変更データを受信すると聞いていますが
冒頭の通りリストの自動更新が動きません

●検索で上位に上がってくるサイトを参考にしながら確認しましたがイマイチ原因がわかりません
誤っている部分や、そもそも考え方が誤っている部分が多分に含まれていると思いますのでご指摘いただけないでしょうか?

該当のソースコード

main

1void main() { 2 runApp( 3 MultiProvider( 4 providers: [ 5 ChangeNotifierProvider<Data1Notifier>(create: (context) => Data1Notifier()), 6 ChangeNotifierProvider<Data2Notifier>(create: (context) => Data2Notifier()), 7 ChangeNotifierProvider<Data3Notifier>(create: (context) => Data3Notifier()), 8 ], 9 child: MyApp(), 10 ), 11 ); 12} 13 14class MyApp extends StatelessWidget { 15 ~省略~ 16} 17 18 19class MainPage extends StatefulWidget { 20 MainPage({Key? key}) : super(key: key); 21 22 @override 23 _MainPageState createState() => _MainPageState(); 24} 25 26class _MainPageState extends State<MainPage> with WidgetsBindingObserver { 27 int _selectedIndex = 0; 28 late PageController _pageController; 29 30 @override 31 Widget build(BuildContext context) { 32 initializeDateFormatting('ja'); 33 34 return Scaffold( 35 appBar: AppBar( 省略 ), 36 body: PageView( 37 controller: _pageController, 38 onPageChanged: (index) { 39 setState(() => _selectedIndex = index); 40 }, 41 children: _pageList), 42 bottomNavigationBar: BottomAppBar( 43 height: 120.w, 44 child: Container( 45 width: 600.w, 46 child: Row( 47 mainAxisAlignment: MainAxisAlignment.spaceBetween, 48 children: [ 49 Container(width: 30), 50 IconButton( 51 onPressed: () { 52 _selectedIndex = 0; 53 _pageController.animateToPage(_selectedIndex, duration: Duration(seconds: 1), curve: Curves.easeInOutCubic); 54 }, 55 icon: Icon(Icons.account_circle_rounded, size: 60.sp, color: white), 56 ), 57 Spacer(), 58 IconButton( 59 onPressed: () async { 60 Navigator.of(context).push(PageRouteBuilder( 61 pageBuilder: (context, animation, secondaryAnimation) => Page1(), 62 transitionsBuilder: (context, animation, secondaryAnimation, child) { 63 final Animatable<Offset> tween = Tween(begin: Offset(0.0, 1.0), end: Offset.zero).chain(CurveTween(curve: Curves.easeInOut)); 64 final Animation<Offset> offsetAnimation = animation.drive(tween); 65 return SlideTransition(position: offsetAnimation, child: child); 66 })); 67 }, 68 icon: Icon(Icons.add, size: 60.sp, color: white), 69 ), 70 Spacer(), 71 IconButton( 72 onPressed: () { 73 _selectedIndex = 1; 74 _pageController.animateToPage(_selectedIndex, duration: Duration(seconds: 1), curve: Curves.easeInOutCubic); 75 }, 76 icon: Icon(Icons.business, size: 60.sp, color: white), 77 ), 78 Container(width: 30), 79 ], 80 ), 81 ), 82 ), 83 ); 84 }

Page1

1class Page1 extends StatefulWidget { 2 const Page1({Key? key}) : super(key: key); 3 4 @override 5 State<Page1> createState() => _Page1State(); 6} 7 8class _Page1State extends State<Page1> { 9 @override 10 Widget build(BuildContext context) { 11 final Data2 = Provider.of<Data2Notifier>(context, listen: false); 12 final Data1 = Provider.of<Data1Notifier>(context); 13 14 return Scaffold( 15 body: FutureBuilder( 16 future: Data2.getData(context), 17 builder: (context, snapshot) { 18 if (snapshot.connectionState == ConnectionState.waiting) { 19 return _loading(); //データロード中の場合 20 } 21 22 if (snapshot.hasError) { 23 return errUI(context); //エラーが起きた場合 24 } 25 26 if (Data2.items.length == 0) { 27 return _noData(context); //データ件数ゼロの場合 28 } 29 30 return Consumer<Data2Notifier>( 31 builder: (context, value, child) { 32 return _cardList(context, Data1,value.data); //データ件数1以上存在の場合 33 }, 34 ); 35 }), 36 ); 37 } 38}

Data2Notifier

1class Data2Notifier extends ChangeNotifier { 2 List items = []; 3 4 Future getData(context) async { 5 final Data1 = Provider.of<Data1Notifier>(context,listen: false); 6 Map<String, dynamic> postData = {"client_id": Data.code}; 7 8 final response = await http.post( 9 Uri.parse("${Data1.url}/dummy/dummy"), 10 headers: { 11 "Content-Type": "application/json", 12 }, 13 body: json.encode(postData), 14 ); 15 16 print(response.statusCode); 17 if (response.statusCode == 200) { 18 var result = GetExistData.fromJson(jsonDecode(response.body)); 19 items = result.items; 20 } else { 21 throw "error"; 22 } 23 } 24 25 notifyListeners(); 26} 27 28class GetExistData { 29 final List items; 30 31 GetExistData({required this.items}); 32 33 factory GetExistData.fromJson(Map<String, dynamic> json) => GetExistData(items: json['data']); 34}

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

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

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

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

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

ta.fu

2023/03/02 08:11

Page2のソースは? 後実現したいことは「Page2でDBに登録したらPage1に表示されているリストに表示するデータを最新のDBのものにしたい」ということなのかな? だけどPage2でDBに登録してもPage1のリストが更新されないということ?
退会済みユーザー

退会済みユーザー

2023/03/02 10:11 編集

>Page2のソースは? Page1:DBからデータを持ってきてリスト表示 Page2:DBへデータを登録 となっています。 それぞれ独立した通信で連携しているわけではないので省いています 強いて言えば 戻るボタンの onPressedは下記のようになっています ----------------------------------------------------- Provider<Data2Notifier>(context).GetExistData() Navigator.of(context).popUntil((route) => route.isFirst); ----------------------------------------------------- >「Page2でDBに登録したらPage1に表示されているリストに表示するデータを最新のDBのものにしたい」 その通りです RefreshIndicatorによる手動リロードは問題ないので、 何らかのトリガーで自動的にリロードするのが理想と考えています 最悪 setState((){}) を入れれば強引にリロードさせる事ができるのは分かっていますが Page2の呼び出し元がMainPage なのでPage1には使えない状況です
ta.fu

2023/03/02 11:28

第3者が追試できるソースが提示されていない状況で、答えを探すのはたぶん難しいのでは。 あえて言うならPage1でwatchしているであろうData1Notifierに、その中でnotifyListenersを呼び出しているメソッドをPage2でコールするというぐらいかな。 これもData1Notifierの役割が分からないのであてずっぽになってしまうけど。
退会済みユーザー

退会済みユーザー

2023/03/02 12:48

・Data1NotifierについてはHTTP通信の時に使うURL/ID/PASSを放り込んで  独立した複数の通信処理で共有しています (このような使い方が正しいのかわかりませんが・・・) ・Data2Notifierは前述の通りPage1で使用しています ・Data3Notifierは現状未使用で空です(本問題を解決したら別機能で使用する予定です) 名前付けが紛らわしく申し訳ありません
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問