我正在做一个有Firestore db后端的应用程序,因为我不需要从应用程序中更新任何东西,而且数据是相当静态的,我想在应用程序初始化时将所有Firestore数据反序列化为Dart数据结构(理想情况下是反序列化到提供者中),以避免在我的Widget类中到处都是Future/StreamBuilder。
Firestore中的数据结构如下
Route
|->Room
|->Point of Interest这是Provider类
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的repository类的摘录
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视图,我尝试了上面代码的一些变体,但似乎不起作用,提供者中的数据总是一个空列表,老实说,我甚至不知道我想要做的是不是对于Flutter应用程序应该如何工作是“正确的”,但我正在尽可能多地了解……
据我测试,从缓存中读取数据并不是问题,因为它会尝试缓存,然后移动到Source.server (但我用Source.server尝试过,但无论如何都不能工作),当已经有缓存的数据时,应用程序工作得很好,并且在没有缓存数据的情况下进行调试,存储库方法实际上是从Firestore中检索数据,所以与数据库的连接也是很好的。
发布于 2021-02-22 11:11:20
好吧,事实证明我从缓存中读取是错误的,正确的方法是(显然,如果你总是想要强制从缓存中读取)
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: Source.Cache));
if (routeContent.docs.length > 0) {
...
} else {
routeContent = await _db.collection('content')
.where("type", isEqualTo: "route")
.orderBy("order", descending: false)
.get(GetOptions(source: Source.Server));
...
}
return routes;
}这个方法尝试从缓存中读取,然后从服务器读取,所以在第一个应用程序运行时,它将从服务器读取,然后在随后的运行中,它将始终从缓存中读取,我希望这能对某些人有所帮助:)不管怎样,如果您对整个解决方案有一些观察,将非常感谢!
https://stackoverflow.com/questions/66309090
复制相似问题