【发布时间】:2021-05-24 07:19:27
【问题描述】:
我正在开发一个带有 Firestore 数据库后端的应用程序,因为我不需要从应用程序更新任何内容并且数据是非常静态的,我想在应用程序初始化时将所有 Firestore 数据反序列化为 Dart 数据结构(理想情况下放入 Provider)以避免在我的 Widget 类中出现 Future/StreamBuilders。
Firestore 中的数据结构如下
Route
|->Room
|->Point of Interest
这是提供者类
class AppData with ChangeNotifier {
static final FirebaseRepo _repo = new FirebaseRepo();
List<model.Route> _routes;
List<model.Route> get routes => _routes;
set routes(List<model.Route> routes) {
_routes = routes;
notifyListeners();
}
AppData() {
_loadData();
}
Future<void> _loadData() async {
routes = await _repo.findAllRoutes();
}
// some get methods that operate on _routes
}
这是我加载routes的存储库类的摘录
class FirebaseRepo {
FirebaseFirestore _db = FirebaseFirestore.instance;
Source _dbSource = Source.cache;
Future<List<model.Route>> findAllRoutes() async {
List<model.Route> routes = [];
var routeContent = await _db.collection('content')
.where("type", isEqualTo: "route")
.orderBy("order", descending: false)
.get(GetOptions(source: _dbSource));
if (routeContent.docs.length > 0) {
await Future.forEach(routeContent.docs, (snapshot) async {
model.Route route = await loadRouteFromSnapshot(snapshot);
route.rooms = await findRouteRooms(route.id);
routes.add(route);
});
}
return routes;
}
Future<List<Room>> findRouteRooms(String routeId) async {
List<Room> rooms = [];
var roomContent = await _db.collection('content')
.doc(routeId)
.collection("rooms")
.orderBy("order", descending: false)
.get(GetOptions(source: _dbSource));
if (roomContent.docs.length > 0) {
await Future.forEach(roomContent.docs, (snapshot) async {
Room room = await loadRoomFromSnapshot(snapshot, routeId);
room.pois = await findRoomPois(room.parentRouteId, room.id);
rooms.add(room);
});
}
return rooms;
}
Future<List<Poi>> findRoomPois(String routeId, String roomId) async {
List<Poi> pois = [];
var poiContent = await _db.collection('content')
.doc(routeId)
.collection("rooms")
.doc(roomId)
.collection("poi")
.orderBy("order", descending: false)
.get(GetOptions(source: _dbSource));
if (poiContent.docs.length > 0) {
await Future.forEach(poiContent.docs, (snapshot) async {
Poi poi = await loadPoiFromSnapshot(snapshot, routeId, roomId);
pois.add(poi);
});
}
return pois;
}
................
}
这是主类
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(CatedralApp());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.white,
fontFamily: 'Alata',
),
routes: {
RouteDetail.routeName: (context) => RouteDetail(),
RoomDetail.routeName: (context) => RoomDetail(),
PoiDetail.routeName: (context) => PoiDetail(),
},
home: LoadingScreen()
);
}
}
class LoadingScreen extends StatelessWidget{
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider.value(
value: AppData(),
child: Consumer<AppData> (
builder: (BuildContext context, AppData provider, Widget child) {
if (provider.routes != null) {
return Home();
} else {
return Stack(
children: <Widget>[
Container(
alignment: Alignment.center,
color: Colors.white,
child: Image.asset('assets/img/splash_background.png'),
),
Container(
alignment: Alignment(0.0, 0.0),
child: Image.asset(
'assets/img/icon.png',
height: 200,
width: 200,
),
)
],
);
}
}
)
);
}
}
这个想法是在数据加载时显示启动画面,然后转到 Home 视图,我尝试了上述代码的一些变体,但它似乎不起作用,Provider 中的数据始终是一个空列表,老实说,我什至不知道我想要做的对于 Flutter 应用程序的工作方式是否“正确”,但我正在尝试尽可能多地理解......
据我测试,从缓存读取不是问题,因为它会尝试缓存,然后移动到 Source.server(但我用 Source.server 尝试过,但它无论如何都不起作用),当已经有缓存数据应用程序工作正常,并且通过在没有缓存数据存在时调试它,存储库方法实际上从 Firestore 检索数据,因此与数据库的连接也很好。
【问题讨论】:
标签: firebase flutter dart google-cloud-firestore deserialization