66419


現在Flutterの勉強としてStreamBuilderを使用して簡単なRSSリーダーを作成しています。  
StreamBuilderを使用してRSSフィードを取得（http.getによって取得）してリスト表示するところまではできました。  
また、画面をオーバースクロールすることで新しいフィードを取得してリストに追加することもできました。  
しかし、オーバースクロールして新しいフィードを取得している時にローディング画面を出すことができずにいます。具体的には、オーバースクロールすることで新しいフィードの取得は開始されますが、このフィードの取得状態(取得処理中なのか、取得処理完了なのか)をどのようにして補足できるのかがわかりません。  
当初はconnectionStateがwaitingであるかどうかで補足できると考えておりましたが、  
connectionStateは常にactive状態になっており、思う動作を実現できませんでした。  
Flutter、Streamについて理解が不足している部分が多々あるため、質問自体が不明瞭かもしれませんが、何かしらヒントや解決策、読むべきドキュメント等あればご教示頂きたいです。  
よろしくお願いします。

[code]

    import 'dart:async';
    import 'package:flutter/material.dart';
    import 'package:intl/intl.dart';
    import 'package:./entry_model.dart';
    
    class EntryList extends StatefulWidget {
    
      @override
      _EntryListState createState() => _EntryListState();
    }
    
    class _EntryListState extends State<EntryList>
        with
            AutomaticKeepAliveClientMixin<EntryList> {
      EntriesModel entriesModel;
      StreamController _itemsController;
      final GlobalKey<ScaffoldState> scaffoldkey = new GlobalKey<ScaffoldState>();
      final formatter = DateFormat('yyyy/MM/dd(E) HH:mm', 'ja_JP');
    
      Future fetchEntries() async {
        final response = await entriesModel.getEntries();
        return response;
      }
    
      Future fetchNewEntries() async {
        final response = await entriesModel.getNewEntries();
        return response;
      }
    
      loadEntries() async {
        fetchEntries().then((res) async {
          _itemsController.add(res);
          return res;
        });
      }
    
      loadNewEntries() async {
        fetchNewEntries().then((res) async {
          _itemsController.add(res);
          return res;
        });
      }
    
      @override
      bool get wantKeepAlive => true;
    
      @override
      void initState() {
        entriesModel = EntriesModel();
        _itemsController = StreamController();
        loadEntries();
        super.initState();
      }
    
      @override
      void dispose() {
        _itemsController.close();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        var numberOfItem = 0;
    
        return Scaffold(
          key: scaffoldkey,
          backgroundColor: Colors.white,
          body: Column(
            children: <Widget>[
              Expanded(
                  flex: 1,
                  child: // オーバースクロールで新しいフィードを取得中にここでローディング中であるメッセージを表示したい。,
              ),
              Expanded(
                flex: 20,
                child: StreamBuilder(
                  stream: _itemsController.stream,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
    
                      numberOfItem = snapshot.data.length as int;
    
                      return numberOfItem == 0
                          ? Center(child: const Text('Empty'))
                          : RefreshIndicator(
                          onRefresh: () => _onRefresh(),
                          child: ListView.builder(
                              itemCount: snapshot.data == null
                                  ? 0
                                  : numberOfItem,
                              itemBuilder: (context, index) {
                                final item = snapshot.data[index] as Entry;
                                return _buildCard(item, index, context)
                              })
                           );
                    } else {
                      return const Text('No data');
                    }
                  },
                ),
              )
            ],
          ),
        );
      }
    
      Future<void> _onRefresh() async {
        await loadNewEntries();
      }
    }
    
    Card _buildCard(Entry item, int index, BuildContext context) {
      return Card( // 各フィードをCard形式で表示 
      );
    }
    
    
[/code]

上記のコード内のEntriesModelがフィードを扱うモデルで、getEntries()でSQLiteに保存しているフィードを読み込んで、getNewEntries()でhttp.getを使って新しいフィードを読み込んでいます。


CC BY-SA 4.0
2019-11-20T06:02:17.660
60684
2020-05-08T05:10:57.720
9875
question
stream flutter
FlutterのStreamBuilderでローディングしているかどうかを補足したい


`_itemsController`にはデータしか流れないため、状態までは分からないですね。  
そのため状態も分かるようにするため、状態用のクラスを用意し、データはこのクラスに内包させる方法はどうでしょうか。

**状態用のクラス**

[code]

    abstract class FetchState {}
    
    class Fetching extends FetchState {}
    
    class Fetched extends FetchState {
      Fetched({this.entryList});
      /// 取得したデータ
      List<Entry> entryList;
    }
    
[/code]

**データ取得の実装**

[code]

    loadEntries() async {
      _itemsController.add(Fetching());
      fetchEntries().then((res) async {
        _itemsController.add(Fetched(entryList: res));
        return res;
      });
    }
    
[/code]

**StreamBuilderの実装**

[code]

    child: StreamBuilder(
      stream: _itemsController.stream,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          if (snapshot.data is Fetching) {
            // データ取得中
            ～処理～
          } else if (snapshot.data is Fetched) {
            // データ取得完了
            // snapshot.data.entryList からデータを取得
            ～処理～
          }
        }
      },
    ),
    
[/code]


CC BY-SA 4.0
2020-05-08T05:10:57.720
66419
2020-05-08T05:10:57.720
40046
60684
answer