带有REST JSON分页的Flutter FutureBuilder

发布时间:2020-07-07 16:14

我用这种方法将JSON数据带到Future<List<Data>> _DataList;https://nomer.biz.ua/mobile/kievstar?page=1

之类的网址
Future<List<Data>> getData(int pageCount) async {
String url = Uri.encodeFull("https://nomer.biz.ua/mobile/kievstar?page=$pageCount");
var response = await http.get(url, headers: {"Accept": "application/json"}).timeout(const Duration(seconds: 10));
final Map res = json.decode(response.body);
Response model = Response.fromJson(res);
page++;
return model.data;
}

并将它们传递给FutureBuilder

@override
 Widget build(BuildContext context) {
  return Scaffold(
    body:FutureBuilder(
      future: _DataList,
       builder: (BuildContext ctx, AsyncSnapshot<dynamic> snapshot){

         if (snapshot.connectionState != ConnectionState.done) {
             return Center(child: CircularProgressIndicator());
        }

        if (snapshot.hasError) {
          return Center(child: Text("Error"));
        }
        if (!snapshot.hasData) {
          return Center(child: Text("Error"));
        }

        var  dataToShow = snapshot.data;

        return  ListView.builder(
           controller: _controller,
           itemCount: dataToShow == null ? 0 : dataToShow.length,
           itemBuilder: (context, index) {
             final item = dataToShow[index];
             return Card(
                  //SHOW DATA 
             );
           });
  }
  )
);
}

在上调用新页面

  @override
  void initState() {
     _DataList = getData(page);

    super.initState();
    _controller.addListener(() {
      if (_controller.position.pixels == _controller.position.maxScrollExtent) {
        _DataList= getData(page);
      }
    });
  }

显示第一页,但其他页面未处理。在将列表滚动到其最后一个元素时,我加载了一个新页面。 _DataList = getData(page);从2个页面接收JSON数据,但没有将它们传递给FutureBuilder。 我找不到真正的示例,其中实现了URL页面导航以及FutureBuilder一起使用。

回答1

您可以在下面复制粘贴运行完整代码
出于演示目的,我将新页面的数据插入旧数据之前,以更好地查看效果
步骤1:您可以将数据解析为模型Payload,可以看到完整的代码以获取详细信息
步骤2:插入新数据并返回_DataList
步骤3:定义_future以避免不必要的重建

代码段

Future<List<Datum>> getData(int pageCount) async {
    String url =
        Uri.encodeFull("https://nomer.biz.ua/mobile/kievstar?page=$pageCount");
    var response = await http.get(url, headers: {
      "Accept": "application/json"
    }).timeout(const Duration(seconds: 10));
    Payload payload = payloadFromJson(response.body);
    _DataList.insertAll(0, payload.data);
    page++;
    return _DataList;
  }

  @override
  void initState() {
    _future = getData(page);

    super.initState();
    _controller.addListener(() {
      if (_controller.position.pixels == _controller.position.maxScrollExtent) {
        setState(() {
          _future = getData(page);
        });
      }
    });
  }
  
FutureBuilder(
            future: _future,  

工作演示

enter image description here

完整代码

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));

String payloadToJson(Payload data) => json.encode(data.toJson());

class Payload {
  Payload({
    this.currentPage,
    this.data,
    this.firstPageUrl,
    this.from,
    this.lastPage,
    this.lastPageUrl,
    this.nextPageUrl,
    this.path,
    this.perPage,
    this.prevPageUrl,
    this.to,
    this.total,
  });

  int currentPage;
  List<Datum> data;
  String firstPageUrl;
  int from;
  int lastPage;
  String lastPageUrl;
  String nextPageUrl;
  String path;
  int perPage;
  dynamic prevPageUrl;
  int to;
  int total;

  factory Payload.fromJson(Map<String, dynamic> json) => Payload(
        currentPage: json["current_page"],
        data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
        firstPageUrl: json["first_page_url"],
        from: json["from"],
        lastPage: json["last_page"],
        lastPageUrl: json["last_page_url"],
        nextPageUrl: json["next_page_url"],
        path: json["path"],
        perPage: json["per_page"],
        prevPageUrl: json["prev_page_url"],
        to: json["to"],
        total: json["total"],
      );

  Map<String, dynamic> toJson() => {
        "current_page": currentPage,
        "data": List<dynamic>.from(data.map((x) => x.toJson())),
        "first_page_url": firstPageUrl,
        "from": from,
        "last_page": lastPage,
        "last_page_url": lastPageUrl,
        "next_page_url": nextPageUrl,
        "path": path,
        "per_page": perPage,
        "prev_page_url": prevPageUrl,
        "to": to,
        "total": total,
      };
}

class Datum {
  Datum({
    this.id,
    this.nomerT,
    this.datumOperator,
    this.ourPrice,
  });

  int id;
  String nomerT;
  Operator datumOperator;
  int ourPrice;

  factory Datum.fromJson(Map<String, dynamic> json) => Datum(
        id: json["id"],
        nomerT: json["nomer_t"],
        datumOperator: operatorValues.map[json["operator"]],
        ourPrice: json["our_price"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "nomer_t": nomerT,
        "operator": operatorValues.reverse[datumOperator],
        "our_price": ourPrice,
      };
}

enum Operator { KV }

final operatorValues = EnumValues({"kv": Operator.KV});

class EnumValues<T> {
  Map<String, T> map;
  Map<T, String> reverseMap;

  EnumValues(this.map);

  Map<T, String> get reverse {
    if (reverseMap == null) {
      reverseMap = map.map((k, v) => new MapEntry(v, k));
    }
    return reverseMap;
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int page = 1;
  List<Datum> _DataList = [];
  Future<List<Datum>> _future;
  ScrollController _controller = ScrollController();

  Future<List<Datum>> getData(int pageCount) async {
    String url =
        Uri.encodeFull("https://nomer.biz.ua/mobile/kievstar?page=$pageCount");
    var response = await http.get(url, headers: {
      "Accept": "application/json"
    }).timeout(const Duration(seconds: 10));
    Payload payload = payloadFromJson(response.body);
    _DataList.insertAll(0, payload.data);
    page++;
    return _DataList;
  }

  @override
  void initState() {
    _future = getData(page);

    super.initState();
    _controller.addListener(() {
      if (_controller.position.pixels == _controller.position.maxScrollExtent) {
        setState(() {
          _future = getData(page);
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: FutureBuilder(
            future: _future,
            builder: (BuildContext ctx, AsyncSnapshot<List<Datum>> snapshot) {
              if (snapshot.connectionState != ConnectionState.done) {
                return Center(child: CircularProgressIndicator());
              }

              if (snapshot.hasError) {
                return Center(child: Text("Error"));
              }
              if (!snapshot.hasData) {
                return Center(child: Text("Error"));
              }

              var dataToShow = snapshot.data;

              return ListView.builder(
                  controller: _controller,
                  itemCount: dataToShow == null ? 0 : dataToShow.length,
                  itemBuilder: (context, index) {
                    final item = dataToShow[index];
                    return Card(
                      child: ListTile(
                        title: Text(dataToShow[index].id.toString()),
                        subtitle: Text(dataToShow[index].ourPrice.toString()),
                      ),
                    );
                  });
            }));
  }
}