在我更新到flutter的新版本之前(见下文),一切正常。 现在它不再有用了。
以下代码执行gridView
的“分页”加载有人可以告诉我Flutter的最新版本有什么变化以及如何解决这个问题?
非常感谢
Flutter版本:
flutter --version
Flutter 0.2.8 • channel beta • https://github.com/flutter/flutter.git
Framework • revision b397406561 (11 days ago) • 2018-04-02 13:53:20 -0700
Engine • revision c903c217a1
Tools • Dart 2.0.0-dev.43.0.flutter-52afcba357
以下是以前使用的代码:
typedef Future<PageAnswer> ApiPageRequest(int page, int pageSize);
class MIDApi {
///
/// Returns the list of items belonging to the active profile
///
Future<PageAnswer> getItems({
int pageIndex: 0,
int pageSize: 50,
@required String sortOrder
}) async {
String url = "ItemsList/$sortOrder";
return ajaxGet(url).then((String responseBody) async {
// print(responseBody);
final Map response = json.decode(responseBody);
final _status = response["status"];
if (_status == "OK"){
// Everything is OK
Map map = json.decode(response["data"]);
List<Map> objects = map["List"];
int total = map["Total"];
return new PageAnswer(objects, total);
}
return Null;
}).catchError((){
return Null;
});
}
}
///
/// This widget is used to display a "paged" GridView
///
/// Invocation example:
/// new PagedGridView<Map>(request, widgetAdapter: adapt);
///
/// where: request could be
/// Future<List<Map>> request(int page, int pageSize) async {
/// routine to fetch the data from the server
/// }
///
/// and adapt could be:
/// Widget adapt(Map map){
/// return new MyWidget(map);
/// }
///
class PagedGridView extends StatefulWidget {
/// Abstraction for loading the data.
/// This can be anything: An API-Call,
/// loading data from a certain file or database,
/// etc. If will deliver a list of objects (of type T)
final ApiPageRequest pageRequest;
/// The number of columns per row of the grid
final int numberColumns;
/// The number of elements requested for each page
final int pageSize;
/// The number of left-over elements in list which
/// will trigger loading the next page
final int pageThreshold;
/// Used for building Widgets out of the fetched data
final WidgetAdapter<Map> widgetAdapter;
final bool reverse;
final Indexer<Map> indexer;
final Stream<Map> topStream;
/// Constructor
const PagedGridView({
Key key,
this.numberColumns: 2,
this.pageSize: 50,
this.pageThreshold: 10,
@required this.pageRequest,
@required this.widgetAdapter,
this.reverse: false,
this.indexer,
this.topStream
}): super(key: key);
@override
State<StatefulWidget> createState() {
return new PagedGridViewState();
}
}
class PagedGridViewState extends State<PagedGridView> {
/// Contains all fetched elements ready to display
List<Map> objects = [];
/// Total number of objects that could be returned
int total = -1;
/// A Future returned by loadNext() if there
/// is currently a request running
/// or null, if no request is performed
Future request;
Map<int, int> index = {};
void doSomething(){
print("I need to do something");
}
void Clear() async {
await onRefresh();
}
@override
void initState(){
super.initState();
/// At start, let's systematically try to fetch some data
this.lockedLoadNext();
if (widget.topStream != null){
widget.topStream.listen((Map t){
setState((){
this.objects.insert(0, t);
this.reIndex();
});
});
}
}
@override
Widget build(BuildContext context){
GridView listView = new GridView.builder(
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: widget.numberColumns),
itemBuilder: itemBuilder,
itemCount: objects.length,
reverse: widget.reverse
);
RefreshIndicator refreshIndicator = new RefreshIndicator(
onRefresh: onRefresh,
child: listView
);
return new NotificationListener<ListElementUpdate<Map>>(
child: refreshIndicator,
onNotification: onUpdate
);
}
Widget itemBuilder(BuildContext context, int index){
/// If we are entering the threshold zone,
/// try to fetch additional objects
if (index + widget.pageThreshold > objects.length){
notifyThreshold();
}
return widget.widgetAdapter != null ? widget.widgetAdapter(objects[index])
: new Container();
}
void notifyThreshold(){
lockedLoadNext();
}
bool onUpdate(ListElementUpdate<Map> update){
if (widget.indexer == null){
debugPrint('ListElementUpdate on un-indexed list');
return false;
}
int index = this.index[update.key];
if (index == null){
debugPrint('ListElementUpdate index not found');
return false;
}
setState((){
this.objects[index] = update.instance;
});
return true;
}
Future onRefresh() async {
this.request?.timeout(const Duration());
PageAnswer answer = await widget.pageRequest(0, widget.pageSize);
List<Map> fetched = answer.list;
total = answer.total;
setState(() {
this.objects.clear();
this.index.clear();
this.addObjects(fetched);
});
return true;
}
///
/// This routine only fetches new data, if no other request is pending
///
void lockedLoadNext() {
if (this.request == null) {
this.request = loadNext().then((x) {
this.request = null;
});
}
}
Future loadNext() async {
// If there is no need to fetch any further data, simply return
if (objects.length >= total && total != -1){
return Null;
}
int page = (objects.length / widget.pageSize).floor();
PageAnswer answer = await widget.pageRequest(page, widget.pageSize);
List<Map> fetched = answer.list;
total = answer.total;
if (mounted) {
this.setState(() {
addObjects(fetched);
});
}
}
void addObjects(Iterable<Map> objects) {
objects.forEach((Map object) {
int index = this.objects.length;
this.objects.add(object);
if (widget.indexer != null) {
this.index[widget.indexer(object)] = index;
}
});
}
void reIndex(){
this.index .clear();
if (widget.indexer!=null){
int i = 0;
this.objects.forEach((object){
index[widget.indexer(object)] == i;
i++;
});
}
}
}
调用代码:
class ItemsPage extends StatefulWidget {
@override
_ItemsPageState createState() => new _ItemsPageState();
}
class _ItemsPageState extends State<ItemsPage> {
static final GlobalKey<PagedGridViewState> _gridKey = new GlobalKey<PagedGridViewState>();
String _path = mid.serverHttps ? "https://${mid.serverUrl}/"
: "http://${mid.serverUrl}/";
String _sortOrder;
final List<SortMethod> sortMethods = const <SortMethod>[
const SortMethod(value: 'alpha', title: "Alpha", icon: Icons.sort_by_alpha),
const SortMethod(value: 'older_first', title: "Older first", icon: Icons.autorenew),
const SortMethod(value: 'last_first', title: "Last first", icon: Icons.change_history),
];
Future<PageAnswer> request(int page, int pageSize) async {
PageAnswer answer = await mid.api.getItems(sortOrder: _sortOrder);
return answer;
}
void _handleTap(int lookId) {
print('tap:' + lookId.toString());
}
Widget adapt(Map map){
var photos = map["Photos"].split(";");
String photoName = photos[0].split("|")[0];
return new GestureDetector(
onTap: () {_handleTap(map["Id"]);},
child: new GridTile(
child: new Card(
child: new Stack(
fit: StackFit.expand,
children: <Widget>[
new Image.network(_path + photoName,
fit: BoxFit.fitHeight),
new Center(
child: new Text(
map["Title"],
textAlign: TextAlign.center,
)),
],
),
),
),
);
}
_onSortOrderChanged(String value) {
setState((){
_sortOrder = value;
_gridKey.currentState.Clear();
});
}
@override
void initState(){
super.initState();
_sortOrder = 'alpha';
}
@override
Widget build(BuildContext context) {
PagedGridView grid = new PagedGridView(
key: _gridKey,
pageRequest: request,
widgetAdapter: adapt,
numberColumns: 2,
);
DropdownButton ddl = new DropdownButton<String>(
value: _sortOrder,
items: sortMethods.map((SortMethod sort){
return new DropdownMenuItem(
value: sort.value,
child: new Row(children: <Widget>[new Icon(sort.icon), new Text(sort.title)],)
);
}).toList(),
onChanged: _onSortOrderChanged,
);
PopupMenuButton<ItemSorting> popSort = new PopupMenuButton<ItemSorting>(
icon: new Icon(Icons.sort),
itemBuilder: (BuildContext context) => <PopupMenuItem<ItemSorting>> [
const PopupMenuItem<ItemSorting>(
value: ItemSorting.alpha,
child: const Text('Sort Alpha')
),
const PopupMenuItem<ItemSorting>(
value: ItemSorting.last_first,
child: const Text('Sort Last First')
),
const PopupMenuItem<ItemSorting>(
value: ItemSorting.older_first,
child: const Text('Sort Older First')
)
],
onSelected: (ItemSorting action){
_onSortOrderChanged(action.toString().split('.')[1]);
},
);
return new Scaffold(
appBar: new AppBar(
title: new Text('My Items'),
actions: <Widget>[
popSort, //ddl,
],
),
body: new Center(
child: grid,
),
);
}
}
class SortMethod {
const SortMethod({this.title, this.icon, this.value});
final String title;
final IconData icon;
final String value;
}
错误堆栈:
E/flutter (15195): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (15195): type 'Future<Object>' is not a subtype of type 'FutureOr<PageAnswer>' where
E/flutter (15195): Future is from dart:async
E/flutter (15195): Object is from dart:core
E/flutter (15195): FutureOr is from dart:async
E/flutter (15195): PageAnswer is from file:///D:/Development/appli/lib/libraries/function_types.dart
E/flutter (15195):
E/flutter (15195): #0 MIDApi.getItems (file:///D:/Development/appli/lib/libraries/api.dart:35:8)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #1 _ItemsPageState.request (file:///D:/Development/appli/lib/pages/items.dart:30:39)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #2 PagedGridViewState.loadNext (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:191:38)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #3 PagedGridViewState.lockedLoadNext (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:178:22)
E/flutter (15195): #4 PagedGridViewState.initState (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:93:10)
E/flutter (15195): #5 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3734:58)
E/flutter (15195): #6 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3600:5)
E/flutter (15195): #7 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #8 Element.updateChild (package:flutter/src/widgets/framework.dart:2693:12)
E/flutter (15195): #9 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4637:14)
E/flutter (15195): #10 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #11 Element.updateChild (package:flutter/src/widgets/framework.dart:2693:12)
E/flutter (15195): #12 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3636:16)
E/flutter (15195): #13 Element.rebuild (package:flutter/src/widgets/framework.dart:3478:5)
E/flutter (15195): #14 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3605:5)
E/flutter (15195): #15 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3600:5)
E/flutter (15195): #16 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #17 Element.updateChild (package:flutter/src/widgets/framework.dart:2693:12)
E/flutter (15195): #18 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3636:16)
E/flutter (15195): #19 Element.rebuild (package:flutter/src/widgets/framework.dart:3478:5)
E/flutter (15195): #20 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3605:5)
E/flutter (15195): #21 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3600:5)
E/flutter (15195): #22 ParentDataElement.mount (package:flutter/src/widgets/framework.dart:3938:11)
E/flutter (15195): #23 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #24 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4742:32)
E/flutter (15195): #25 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #26 Element.updateChild (package:flutter/src/widgets/framework.dart:2693:12)
E/flutter (15195): #27 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3636:16)
E/flutter (15195): #28 Element.rebuild (package:flutter/src/widgets/framework.dart:3478:5)
E/flutter (15195): #29 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3605:5)
E/flutter (15195): #30 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3752:11)
E/flutter (15195): #31 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3600:5)
E/flutter (15195): #32 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #33 Element.updateChild (package:flutter/src/widgets/framework.dart:2693:12)
E/flutter (15195): #34 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3636:16)
E/flutter (15195): #35 Element.rebuild (package:flutter/src/widgets/framework.dart:3478:5)
E/flutter (15195): #36 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3605:5)
E/flutter (15195): #37 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3600:5)
E/flutter (15195): #38 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2890:14)
E/flutter (15195): #39 Element.updateChild (package:flutter/src/widgets/framework.dart:2693:12)
E/flutter (15195): #40 ComponentElement.performRebuild (packag
E/flutter (15195): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (15195): type 'Future<Object>' is not a subtype of type 'FutureOr<PageAnswer>' where
E/flutter (15195): Future is from dart:async
E/flutter (15195): Object is from dart:core
E/flutter (15195): FutureOr is from dart:async
E/flutter (15195): PageAnswer is from file:///D:/Development/appli/lib/libraries/function_types.dart
E/flutter (15195):
E/flutter (15195): #0 MIDApi.getItems (file:///D:/Development/appli/lib/libraries/api.dart:34:8)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #1 _ItemsPageState.request (file:///D:/Development/appli/lib/pages/items.dart:30:39)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #2 PagedGridViewState.onRefresh (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:160:38)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #3 PagedGridViewState.Clear (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:85:11)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #4 _ItemsPageState._onSortOrderChanged.<anonymous closure> (file:///D:/Development/appli/lib/pages/items.dart:67:29)
E/flutter (15195): #5 State.setState (package:flutter/src/widgets/framework.dart:1108:30)
E/flutter (15195): #6 _ItemsPageState._onSortOrderChanged (file:///D:/Development/appli/lib/pages/items.dart:65:5)
E/flutter (15195): #7 _ItemsPageState.build.<anonymous closure> (file:///D:/Development/appli/lib/pages/items.dart:114:9)
E/flutter (15195): #8 _PopupMenuButtonState.showButtonMenu.<anonymous closure> (package:flutter/src/material/popup_menu.dart)
E/flutter (15195): #9 _RootZone.runUnary (dart:async/zone.dart:1381:54)
E/flutter (15195): #10 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
E/flutter (15195): #11 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633:45)
E/flutter (15195): #12 Future._propagateToListeners (dart:async/future_impl.dart:662:32)
E/flutter (15195): #13 Future._completeWithValue (dart:async/future_impl.dart:477:5)
E/flutter (15195): #14 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:507:7)
E/flutter (15195): #15 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (15195): #16 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
I/flutter (15195): Another exception was thrown: type '() => Future<dynamic>' is not a subtype of type '() => Future<Null>'
E/flutter (15195): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (15195): type '() => Type' is not a subtype of type '(Object) => FutureOr<Object>'
E/flutter (15195): #0 _FutureListener.handleError (dart:async/future_impl.dart:145:11)
E/flutter (15195): #1 Future._propagateToListeners.handleError (dart:async/future_impl.dart:645:47)
E/flutter (15195): #2 Future._propagateToListeners (dart:async/future_impl.dart:666:24)
E/flutter (15195): #3 Future._completeError (dart:async/future_impl.dart:485:5)
E/flutter (15195): #4 _SyncCompleter._completeError (dart:async/future_impl.dart:55:12)
E/flutter (15195): #5 _Completer.completeError (dart:async/future_impl.dart:27:5)
E/flutter (15195): #6 MIDApi.getItems.<anonymous closure> (file:///D:/Development/appli/lib/libraries/api.dart)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #7 _RootZone.runUnary (dart:async/zone.dart:1381:54)
E/flutter (15195): #8 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
E/flutter (15195): #9 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633:45)
E/flutter (15195): #10 Future._propagateToListeners (dart:async/future_impl.dart:662:32)
E/flutter (15195): #11 Future._complete (dart:async/future_impl.dart:467:7)
E/flutter (15195): #12 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
E/flutter (15195): #13 ajaxGet (file:///D:/Development/appli/lib/libraries/ajax.dart)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #14 MIDApi.getItems (file:///D:/Development/appli/lib/libraries/api.dart:21:12)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #15 _ItemsPageState.request (file:///D:/Development/appli/lib/pages/items.dart:30:39)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #16 PagedGridViewState.onRefresh (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:160:38)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #17 PagedGridViewState.Clear (file:///D:/Development/appli/lib/widgets/paged_grid_view.dart:85:11)
E/flutter (15195): <asynchronous suspension>
E/flutter (15195): #18 _ItemsPageState._onSortOrderChanged.<anonymous closure> (file:///D:/Development/appli/lib/pages/items.dart:67:29)
E/flutter (15195): #19 State.setState (package:flutter/src/widgets/framework.dart:1108:30)
E/flutter (15195): #20 _ItemsPageState._onSortOrderChanged (file:///D:/Development/appli/lib/pages/items.dart:65:5)
E/flutter (15195): #21 _ItemsPageState.build.<anonymous closure> (file:///D:/Development/appli/lib/pages/items.dart:114:9)
E/flutter (15195): #22 _PopupMenuButtonState.showButtonMenu.<anonymous closure> (package:flutter/src/material/popup_menu.dart)
E/flutter (15195): #23 _RootZone.runUnary (dart:async/zone.dart:1381:54)
E/flutter (15195): #24 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
E/flutter (15195): #25 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:633:45)
E/flutter (15195): #26 Future._propagateToListeners (dart:async/future_impl.dart:662:32)
E/flutter (15195): #27 Future._completeWithValue (dart:async/future_impl.dart:477:5)
E/flutter (15195): #28 Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:507:7)
E/flutter (15195): #29 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (15195): #30 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)