我正在尝试复制此视频中显示的黑客新闻应用程序:https://youtu.be/fahC3ky_zW0。但是在我的StreamBuilder
快照连接状态中,总是处于“等待”状态。因此,我的应用程序无法填充数据。
文件:hn_bloc.dart
class HackerNewsBloc {
final _articlesSubject = BehaviorSubject<UnmodifiableListView<Article>>();
var _articles = <Article>[];
List<int> _ids = [
23361987,
23366546,
];
HackerNewBlock() {
_updateArticles().then((_) {
_articlesSubject.add(UnmodifiableListView(_articles));
});
}
Stream<UnmodifiableListView<Article>> get articles => _articlesSubject.stream;
Future<Article> _getArticle(int id) async {
final storyUrl = 'https://hacker-news.firebaseio.com/v0/item/$id.json';
final storyRes = await http.get(storyUrl);
return parseArticle(storyRes.body);
}
Future<Null> _updateArticles() async {
final futureArticles = _ids.map((id) => _getArticle(id));
final articles = await Future.wait(futureArticles);
_articles = articles;
return null;
}
}
文件main.dart
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:hackernews/src/article.dart';
import 'package:hackernews/src/hn_bloc.dart';
import 'dart:collection';
import 'dart:async';
void main() {
final hnBloc = HackerNewsBloc();
runApp(MyApp(
bloc: hnBloc,
));
}
class MyApp extends StatelessWidget {
final HackerNewsBloc bloc;
MyApp({
Key key,
this.bloc,
}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hacker News',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(
title: 'Hacker News',
bloc: bloc,
),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
final HackerNewsBloc bloc;
MyHomePage({Key key, this.title, this.bloc}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: StreamBuilder<UnmodifiableListView<Article>>(
stream: widget.bloc.articles,
initialData: UnmodifiableListView<Article>([]),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start.');
case ConnectionState.active:
case ConnectionState.waiting:
return Text('Awaiting result...');
case ConnectionState.done:
if (snapshot.hasError) return Text('Error: ${snapshot.error}');
return ListView(
children: snapshot.data.map(_buildItem).toList(),
);
// You can reach your snapshot.data['url'] in here
}
return null; // unreachable
},
),
);
}
Widget _buildItem(Article article) {
print(article);
return Padding(
key: Key(article.title),
padding: const EdgeInsets.all(16.0),
child: ExpansionTile(
title: Text(
article.title,
style: TextStyle(fontSize: 24),
),
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("${article.type}"),
IconButton(
icon: Icon(Icons.launch),
onPressed: () async {
if (await canLaunch(article.url)) {
launch(article.url);
}
},
),
],
),
],
),
);
}
}