Flutter中使用来自PHP的API的流(非Firebase)

9
假设我有一个API - 示例:https://jsonplaceholder.typicode.com/posts 现在,我想使用StreamBuilder将其应用于具有ListTiles的ListView。我该如何配置?我该如何为其创建流?
我完全了解firebase和firestore的流。我想知道如果我从PHP获取一个API并且我想构建一个StreamBuilder,我该怎么做。

我其实在 Stream 类型这里有些迷茫。我想创建一个带有 url 的 List View。第一个要求是为 StreamBuilder 创建一个流。其他的快照和构建器都很好理解。只是不确定如何创建 Stream。在大多数情况下,所有人都使用 Firestore 的用户流,而我想知道如果我有自己的来自 PHP 的数据库和 Api,该如何创建 Stream。 - Santu
请查看此链接 https://gist.github.com/bobykurniawan11/abea25eabdf917afb1f16520dfae494f,希望能对您有所帮助。 - Boby
3个回答

12
请参考这篇文档:https://blog.khophi.co/using-refreshindicator-with-flutter-streambuilder/。其中还包含了一段视频。GitHub 代码链接为:https://github.com/seanmavley/refreshindicator-with-streambuilder/blob/master/lib/main.dart。完整示例代码请参见原文。
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Basic Project',
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  StreamController _postsController;
  final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();

  int count = 1;

  Future fetchPost([howMany = 5]) async {
    final response = await http.get(
        'https://blog.khophi.co/wp-json/wp/v2/posts/?per_page=$howMany&context=embed');

    if (response.statusCode == 200) {
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load post');
    }
  }

  loadPosts() async {
    fetchPost().then((res) async {
      _postsController.add(res);
      return res;
    });
  }

  showSnack() {
    return scaffoldKey.currentState.showSnackBar(
      SnackBar(
        content: Text('New content loaded'),
      ),
    );
  }

  Future<Null> _handleRefresh() async {
    count++;
    print(count);
    fetchPost(count * 5).then((res) async {
      _postsController.add(res);
      showSnack();
      return null;
    });
  }

  @override
  void initState() {
    _postsController = new StreamController();
    loadPosts();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(
        title: new Text('StreamBuilder'),
        actions: <Widget>[
          IconButton(
            tooltip: 'Refresh',
            icon: Icon(Icons.refresh),
            onPressed: _handleRefresh,
          )
        ],
      ),
      body: StreamBuilder(
        stream: _postsController.stream,
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          print('Has error: ${snapshot.hasError}');
          print('Has data: ${snapshot.hasData}');
          print('Snapshot Data ${snapshot.data}');

          if (snapshot.hasError) {
            return Text(snapshot.error);
          }

          if (snapshot.hasData) {
            return Column(
              children: <Widget>[
                Expanded(
                  child: Scrollbar(
                    child: RefreshIndicator(
                      onRefresh: _handleRefresh,
                      child: ListView.builder(
                        physics: const AlwaysScrollableScrollPhysics(),
                        itemCount: snapshot.data.length,
                        itemBuilder: (context, index) {
                          var post = snapshot.data[index];
                          return ListTile(
                            title: Text(post['title']['rendered']),
                            subtitle: Text(post['date']),
                          );
                        },
                      ),
                    ),
                  ),
                ),
              ],
            );
          }

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

          if (!snapshot.hasData &&
              snapshot.connectionState == ConnectionState.done) {
            return Text('No Posts');
          }
        },
      ),
    );
  }
}

你的 PHP 中的 JSON 类

// To parse this JSON data, do
//
//     final payload = payloadFromJson(jsonString);

import 'dart:convert';

List<Payload> payloadFromJson(String str) => new List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));

String payloadToJson(List<Payload> data) => json.encode(new List<dynamic>.from(data.map((x) => x.toJson())));

class Payload {
    int userId;
    int id;
    String title;
    String body;

    Payload({
        this.userId,
        this.id,
        this.title,
        this.body,
    });

    factory Payload.fromJson(Map<String, dynamic> json) => new Payload(
        userId: json["userId"],
        id: json["id"],
        title: json["title"],
        body: json["body"],
    );

    Map<String, dynamic> toJson() => {
        "userId": userId,
        "id": id,
        "title": title,
        "body": body,
    };
}

9

经过大量的研究,我尝试使用以下代码解决我的问题 这段代码可以解决从 API 中获取实时数据的问题

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:live_data_stream/provider/Api.dart';
import 'package:live_data_stream/provider/model/AuthModel.dart';

class DetailsView extends StatefulWidget {
  @override
  _DetailsViewState createState() => _DetailsViewState();
}

class _DetailsViewState extends State<DetailsView> {
  StreamController<AuthModel> _userController;
  final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      appBar: new AppBar(
        title: new Text('StreamBuilder Demo'),
        actions: <Widget>[
          IconButton(
            tooltip: 'Refresh',
            icon: Icon(Icons.refresh),
            onPressed: _handleRefresh,
          )
        ],
      ),
      body: StreamBuilder(
        stream: _userController.stream,
        builder: (BuildContext context, AsyncSnapshot<AuthModel> snapshot) {
         switch(snapshot.connectionState){
           case ConnectionState.none:
             return Center(
               child: Text('None'),
             );
             break;
           case ConnectionState.waiting:
             return Center(
               child: CircularProgressIndicator(),
             );
             break;
           case ConnectionState.active:
             return Center(
               child:  Text(
                 snapshot.data.fname == null ? 'Null' : snapshot.data.fname,
                 style: Theme.of(context).textTheme.display1,
               ),
             );
             break;
           case ConnectionState.done:
             print('Done is fucking here ${snapshot.data}');
             if(snapshot.hasData){
               return Center(
                 child:  Text(
                   snapshot.data.fname == null ? 'Null' : snapshot.data.fname,
                   style: Theme.of(context).textTheme.display1,
                 ),
               );
             }else if(snapshot.hasError){
               return Text('Has Error');
             }else{
               return Text('Error');
             }
             break;
         }
         return Text('Non in Switch');
        },
      ),
    );
  }
  @override
  void initState() {
    _userController = new StreamController();
    Timer.periodic(Duration(seconds: 1), (_) => loadDetails());
   // loadDetails();
    super.initState();
  }
  int count = 1;

  loadDetails() async {
    Api().getUserInfo('horlaz229@gmail.com', '123456').then((res) async{
      print('LoadDetails of ${res.fname}');
      _userController.add(res);
      return res;
    });
  }

  showSnack() {
    return scaffoldKey.currentState.showSnackBar(
      SnackBar(
        content: Text('New content loaded'),
      ),
    );
  }

  Future<Null> _handleRefresh() async {
    count++;
    print(count);
    Api().getUserInfo('horlaz229@gmail.com', 'APP-1571216683-766').then((res) async {
      print('New Data of ${res.fname}');
      _userController.add(res);
      showSnack();
      return null;
    });
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _userController.close();
  }
}

0

这对我有效

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

class PeriodicRequester extends StatelessWidget {
Stream<http.Response> getRandomNumberFact() async* {
yield* Stream.periodic(Duration(seconds: 5), (_) {
  return http.get("http://numbersapi.com/random/");
}).asyncMap((event) async => await event);
}

@override
Widget build(BuildContext context) {
return StreamBuilder<http.Response>(
  stream: getRandomNumberFact(),
  builder: (context, snapshot) => snapshot.hasData
      ? Center(child: Text(snapshot.data.body))
      : CircularProgressIndicator(),
);
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接