我正在使用Firestore
数据库存储对象列表。要检索它们,我使用Stream
包提供的Firestore
,如下所示:
class FirestoreApi implements Api {
FirestoreApi._();
static final instance = FirestoreApi._();
@override
Stream<List<Job>> getJobList() {
final path = "users/myUserId/jobs";
final reference = Firestore.instance.collection(path);
final snapshots = reference.snapshots();
return snapshots.map((snapshot) => snapshot.documents.map(
(snapshot) => Job(
id: snapshot.data['uid'],
name: snapshot.data['name']
),
).toList());
}
}
它实现了abstract
类:
abstract class Api {
Stream<List<Job>> getJobList();
}
在我的Repository
类中,我这样称呼它:
class Repository {
final FirestoreApi _firestoreApi = FirestoreApi.instance;
Stream<List<job>> getJobList() => _firestoreApi.getJobList();
}
然后在我的BloC中,我称Repository
:
class JobBloc {
final _repository = new Repository();
Stream<List<Job>> getJobList() {
try {
return _repository.getJobList();
} catch (e) {
rethrow;
} finally {}
}
}
最后是我在Widget
中使用它的方式:
Widget _buildBody(BuildContext context) {
final JobBloc _jobBloc = Provider.of<JobBloc>(context);
return StreamBuilder<List<Job>>(
stream: _jobBloc.getJobList(),
builder: (BuildContext context, AsyncSnapshot<List<Job>> snapshot) {
if (snapshot.hasData) {
return RefreshIndicator(
child: JobList(snapshot.data),
onRefresh: () => _jobBloc.refreshJobList(),
);
} else {
if(snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return Center(child: Text("No data"));
}
}
},
);
}
直到这里,一切都很好,并且当Widget
数据库中发生更改时,我的Firestore
会实时更新。
但是现在我想更进一步。可以说,也许将来我需要更改我的api实现,并使用REST
api代替Firestore
。我希望我的代码为此做好了准备。
在那种情况下,所有的getJobList()
方法都应返回Future<List<Job>>
,因为api
不会返回Stream
(我不知道是否可能)。
我会有另一个api
类,现在返回Future<List<Job>>
:
class RestApi implements Api {
RestApi._();
static final instance = RestApi._();
@override
Future<List<Job>> getJobList() {
//TODO: my rest api implementation
}
}
因此Api
abstract
类将被这样修改:
abstract class Api {
Future<List<Job>> getJobList();
}
这里是更新的Repository
:
class Repository {
final RestApi _restApi = RestApi.instance;
Future<List<job>> getJobList() => _restApi.getJobList();
}
最后在我的Bloc
中,我将sink
api在StreamController
中返回的列表如下:
class JobBloc {
final StreamController _jobController = StreamController<List<Job>>.broadcast();
// retrieve data from stream
Stream<List<Job>> get jobList => _jobController.stream;
Future<List<Job>> getJobList() async {
try {
_jobController.sink.add(await _repository.getJobList());
} catch (e) {
rethrow;
} finally {}
}
}
[现在的问题:我真的很喜欢Firestore
返回一个Stream
,它使我的应用程序得以实时更新。但另一方面,我希望我的体系结构是一致的。
由于无法使我的REST
api返回Stream
,我认为唯一可行的方法是将Firebase
Stream
转换为Future
,但随后我将放弃实时更新功能。
类似这样的东西:
class FirestoreApi implements Api {
FirestoreApi._();
static final instance = FirestoreApi._();
@override
Future<List<Job>> getJobList() async {
final path = "users/myUserId/jobs";
final reference = Firestore.instance.collection(path);
final snapshots = reference.snapshots();
Stream<List<Job>> jobs = snapshots.map((snapshot) => snapshot.documents.map(
(snapshot) => Job(
id: snapshot.data['uid'],
name: snapshot.data['name'],
),
).toList());
List<Job> future = await jobs.first;
return future;
}
}
很长的问题,很抱歉,也许有点难以理解,但是我已经尽力了。
直到现在,我研究的是使用Future
只会返回一个响应,因此我将失去实时功能。
我想知道只是为了使体系结构一致或者是否有更好的方法而失去实时功能是否值得。
预先感谢您的任何想法或建议。
我正在使用Firestore数据库存储对象列表。要检索它们,我使用Firestore包提供的Stream,如下所示:类FirestoreApi实现Api {FirestoreApi ._(); ...
这全取决于您的应用程序。如果实时更新是影响用户体验的重要功能,请坚持使用Firebase数据流。如果不是必须进行实时更新,则可以使用期货获得一次数据。实时数据更新的Firebase替代品可以是GraphQL订阅。我建议您检查Hasura以快速实现GraphQL API。