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

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

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

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

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

非同期処理

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

Dart

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

Q&A

解決済

1回答

2633閲覧

FutureBuilderを使っているときのProviderの書き方について

ringoringogogo

総合スコア15

Flutter

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

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

非同期処理

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

Dart

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

0グッド

0クリップ

投稿2021/05/17 13:43

Androidアプリにおいて保存されたURLからHTMLを解析してアイキャッチ画像とタイトルを取得する画面を作成しています。
取得中は読み込み中のインディケーターを表示させるため、FutureBuilderとProviderを使ってListViewを表示したいと考えています。

Providerを使わない場合は正しく表示されるのですが、リストから削除した時や新しく追加したときに読み込み直さないと表示が変わらないため、Providerを一緒に利用したいと考えており、対処方法がわかる方がいらっしゃいましたらヒントでもなんでも結構ですので教えていただけないでしょうか。

該当画面のコードは以下です。(一部不要な部分は省略)
Widget clipListAreaの前半、②のコードにすると正しく表示はされるのですが、①のようにProviderを使ってみたのですが、後述するエラーとなってしまいます・・
エラーについてはStackOverflowなど含め様々なサイトを見てみたのですが根本的な理解をしていないせいか、Builderで作り直したり、別のWidgetにしてもうまく行きませんでした・・。

dart

1class ClipList extends StatelessWidget { 2 //変数などを宣言 3 4 5 Widget build(BuildContext context) { 6 return clipListArea(context); 7 } 8} 9 10 11Widget clipListArea(context){ 12 return Container( 13 child: FutureBuilder<List<PageData>>( 14 //エラーになるコード・・・① 15 future: Provider.of<ClipListModel>(context, listen: true).request(), 16 17 // このコードにすると正しく表示される・・・② 18 // future:ClipListModel().request(), 19 builder: (ctx, dataSnapshot) { 20 if (dataSnapshot.connectionState == ConnectionState.waiting) { 21 // 非同期処理未完了 = 通信中 22 return Center( 23 child: CircularProgressIndicator(), 24 ); 25 } 26 27 if (dataSnapshot.error != null) { 28 // エラー 29 return Center( 30 child: Text('エラーが発生しました。一度アプリを終了し再度起動してください') 31 ); 32 } 33 34 if(dataSnapshot.data.length==0){ 35 return Center( 36 child:Text('データがありません') 37 ); 38 } 39 return clipListContents(dataSnapshot.data); 40 41 })); 42} 43 44 45 46Widget clipListContents(List<PageData> cliplistdata) { 47 return ListView.builder( 48 physics: AlwaysScrollableScrollPhysics(), 49 itemCount: cliplistdata.length, 50 itemBuilder: (lctx, index) => 51 ( 52 Padding( 53 padding: const EdgeInsets.only(right: 8.0, left: 8.0), 54 child: InkWell( 55 onTap: () { 56 Navigator.of(lctx).push( 57 //画面遷移 58 ) 59 ); 60 }, 61 62 child: Row( 63 mainAxisAlignment: MainAxisAlignment 64 .spaceBetween, 65 children: <Widget>[ 66 //アイキャッチ画像とタイトルを表示 67 ] 68 ) 69 ), 70 ) 71} 72 73 74 75 76

①のコードにしたときのエラー内容

======== Exception caught by widgets library =======================================================
The following ProviderNotFoundException was thrown building ClipList(dirty):
Error: Could not find the correct Provider<ClipListModel> above this ClipList Widget

This happens because you used a BuildContext that does not include the provider
of your choice. There are a few common scenarios:

  • You added a new provider in your main.dart and performed a hot-reload.
    To fix, perform a hot-restart.

  • The provider you are trying to read is in a different route.

    Providers are "scoped". So if you insert of provider inside a route, then
    other routes will not be able to access that provider.

  • You used a BuildContext that is an ancestor of the provider you are trying to read.

    Make sure that ClipList is under your MultiProvider/Provider<ClipListModel>.
    This usually happens when you are creating a provider and trying to read it immediately.

    For example, instead of:

    Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // Will throw a ProviderNotFoundError, because `context` is associated // to the widget that is the parent of `Provider<Example>` child: Text(context.watch<Example>()), ), }

    consider using builder like so:

    Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // we use `builder` to obtain a new `BuildContext` that has access to the provider builder: (context) { // No longer throws return Text(context.watch<Example>()), } ), }

If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter

The relevant error-causing widget was:
ClipList file:///Users/takeyama/AndroidStudioProjects/viewer/lib/main.dart:69:13
When the exception was thrown, this was the stack:
0 Provider._inheritedElementOf (package:provider/src/provider.dart:332:7)
1 Provider.of (package:provider/src/provider.dart:284:30)
2 clipListArea (package:viewer/Clip/cliplist.dart:106:26)
3 ClipList.build (package:viewer/Clip/cliplist.dart:156:12)
4 StatelessElement.build (package:flutter/src/widgets/framework.dart:4569:28)

====================================================================================================

ClipListModelは以下のようにしています。

dart

1class ClipListModel extends ChangeNotifier { 2 List<String> cliplist = []; 3 List<PageData> pagedataList = []; 4 5 Future<List<PageData>> request() async { 6 SharedPreferences prefs = await SharedPreferences.getInstance(); 7 cliplist = //prefsから取得 8 9 for (int i = 0; i < cliplist.length; i++) { 10 PageData tmpPageData = new PageData(); 11 tmpPageData = await fetch(cliplist[i]); 12 pagedataList.add(tmpPageData); 13 } 14 notifyListeners(); 15 return pagedataList; 16 } 17 18 Future<void> trash(deletePageData) async { 19 if(pagedataList!= null){ 20 pagedataList.remove(deletePageData); 21 } 22 23 SharedPreferences prefs = await SharedPreferences.getInstance(); 24 cliplist = //prefsから取得 25 cliplist.remove(deletePageData.url); 26 //prefsにセット 27 28 notifyListeners(); 29 } 30 31 _validateUrl(String url) { 32 if (url?.startsWith('http://') == true || 33 url?.startsWith('https://') == true) { 34 return url; 35 } 36 else { 37 return 'http://$url'; 38 } 39 } 40 41 Future<PageData> fetch(url) async { 42 //引数urlからHTML要素を取得してPageDataの各プロパティにセット 43 } 44 45} 46

その他不足している情報などございましたらご指摘いただけますと幸いです。

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

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

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

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

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

guest

回答1

0

自己解決

以下のようにするとエラーは解消できました。

void main() { runApp( ChangeNotifierProvider<ClipListModel>( create: (context) => ClipListModel(), child:MyApp() )); }

投稿2021/05/20 12:41

ringoringogogo

総合スコア15

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問