与提供者的REST分页如何无限滚动?

时间:2019-09-05 03:48:56

标签: flutter

我使用提供程序包创建了一个Flutter项目 以前,它在this sample项目之后使用ScopedModel运行良好。

我想用相同的逻辑实现v3提供程序,

// main.dart

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(builder: (context) => NoteContentModel()),
      ],
     ...
        home: NoteContentPage(),
      ),
    );
  }

// note_content_model.dart


class NoteContentModel extends ChangeNotifier {
  final _pageSize = 30;

  List<Content> _content = [];
  bool _isLoading = false;
  int _totalResults;
  int _totalPages;
  bool _hasMorePages = true;
  String _placeName;
  bool _isLoadingMore = false;

  // .. other setter getter

  int getNoteCount() => _content.length;

  Future<dynamic> _getData([int page = 1]) async {
    var res = await http.get(getUrl(page));
    return jsonDecode(res.body);
  }

  Future getNoteContent([int page = 1]) async {
    if (page == 1) {
      _isLoading = true;
      _content.clear();
    } else {
      _isLoadingMore = true;
    }

    notifyListeners();

    var responseData = await _getData();

    List noteContent = responseData['content'];
    noteContent.forEach((content) {
      _content.add(Content.fromJson(content));
    });

    _totalResults = responseData['total_count'];
    _totalPages = responseData['page_count'];

    if (responseData['page_number'] == totalPages) {
      _hasMorePages = false;
    }

    if (page == 1) {
      _isLoading = false;
    } else {
      _isLoadingMore = false;
    }
    notifyListeners();
  }

}

// note_content_page.dart


class NoteContentPage extends StatefulWidget {
  @override
  _NoteContentPageState createState() => _NoteContentPageState();
}

class _NoteContentPageState extends State<NoteContentPage> {
  int page = 1;

  ScrollController controller;

  void _scrollListener() {
    final NoteContentModel noteModel = Provider.of<NoteContentModel>(context);
    if (controller.position.pixels == controller.position.maxScrollExtent) {
      if (!noteModel.isLoadingMore && noteModel.hasMorePages) {
        page++;
        print("Current page: $page");
        noteModel.getNoteContent(page);
      }
    }
  }

  @override
  void initState() {
    super.initState();
    controller = new ScrollController()..addListener(_scrollListener);
  }

  @override
  void dispose() {
    super.dispose();
    controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final NoteContentModel noteModel = Provider.of<NoteContentModel>(context);

    // Call initiate first page
    noteModel.getNoteContent(page);

    return Scaffold(
      appBar: AppBar(title: Text("Test")),
      body: CustomScrollView(
        controller: controller,
        slivers: <Widget>[
          noteModel.isLoading
              ? SliverFillRemaining(
                  child: Center(
                    child: CircularProgressIndicator(),
                  ),
                )
              : SliverList(
                  delegate: SliverChildBuilderDelegate(
                    (context, index) {
                      if (index == noteModel.getNoteCount()) {
                        if (noteModel.hasMorePages) {
                          print("here1");
                          return Padding(
                            padding: const EdgeInsets.symmetric(vertical: 16.0),
                            child: Center(child: CircularProgressIndicator()),
                          );
                        }
                        return Container();
                      } else {
                        return Column(
                          children: <Widget>[
                            Padding(
                              padding: const EdgeInsets.all(16.0),
                              child: Text(noteModel.content[index].title),
                              // child: Text("test"),
                            ),
                          ],
                        );
                      }
                    },
                    childCount: noteModel.getNoteCount(),
                  ),
                )
        ],
      ),
    );
  }
}

我总是收到此消息循环markNeedsBuild() called during build结束跟踪错误

I/flutter ( 2525): ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
I/flutter ( 2525): The following assertion was thrown while dispatching notifications for NoteContentModel:
I/flutter ( 2525): setState() or markNeedsBuild() called during build.
I/flutter ( 2525): This ListenableProvider<NoteContentModel> widget cannot be marked as needing to build because the
...
I/flutter ( 2525): #0      Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3670:11)
I/flutter ( 2525): #1      Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3685:6)
I/flutter ( 2525): #2      State.setState (package:flutter/src/widgets/framework.dart:1161:14)
I/flutter ( 2525): #3      __BuilderListenableDelegate&BuilderStateDelegate&_ListenableDelegateMixin.startListening.<anonymous closure> (package:provider/src/listenable_provider.dart:186:36)
I/flutter ( 2525): #4      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:206:21)
I/flutter ( 2525): #5      NoteContentModel.getNoteContent (package:paging_provider/providers/note_content_model.dart:42:5)
I/flutter ( 2525): <asynchronous suspension>
I/flutter ( 2525): #6      _NoteContentPageState.build (package:paging_provider/pages/note_content_page.dart:44:15)
I/flutter ( 2525): #7      StatefulElement.build (package:flutter/src/widgets/framework.dart:4012:27)
I/flutter ( 2525): #8      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3924:15)
I/flutter ( 2525): #9      Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5)
I/flutter ( 2525): #10     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3907:5)
...
// This trace always loop on app running
I/flutter ( 2525): Another exception was thrown: setState() or markNeedsBuild() called during build....

仅此而已,任何回应将不胜感激。

1 个答案:

答案 0 :(得分:0)

您必须将函数包装在 addPostFrameCallback() 中,以便在构建函数完成工作并在屏幕上绘制小部件后提交调用

改变

noteModel.getNoteContent(page);

WidgetsBinding.instance.addPostFrameCallback((_) => noteModel.getNoteContent(page);
 );