Я использую базу данных 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();
}
В своем классе репозитория я вызываюэто так:
class Repository {
final FirestoreApi _firestoreApi = FirestoreApi.instance;
Stream<List<job>> getJobList() => _firestoreApi.getJobList();
}
Затем в моем BloC я вызываю репозиторий:
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 и использовать API REST вместо Firestore. Я хочу, чтобы мой код был подготовлен для этого.
В этом случае все методы getJobList()
должны возвращать Future<List<Job>>
, поскольку API не вернет Stream
(я не знаю, возможно ли это).
Iбудет иметь другой класс 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();
}
Вот обновленный репозиторий:
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
вернет только один ответ, поэтому я потеряю функциональность в реальном времени.
Хотелось бы знать, будет ли потеря функции реального времени приемлемой только для обеспечения согласованности архитектуры или если есть лучший подход.
Заранее спасибо, любые идеи или предложения будутбыть оцененным.
РЕДАКТИРОВАТЬ: Большое спасибо за ваши комментарии, я действительно ценю их. На самом деле я не знаю, какой из них должен быть помечен как принятый ответ, так как все они мне очень помогли, поэтому я решил дать всем вам положительный голос. Если кто-то не согласен с этим или это неправильное поведение в Stackoverflow, пожалуйста, дайте мне знать