首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Flutter:在应用程序初始化时将Firestore数据加载到提供程序中

Flutter:在应用程序初始化时将Firestore数据加载到提供程序中
EN

Stack Overflow用户
提问于 2021-02-22 09:55:50
回答 1查看 164关注 0票数 0

我正在做一个有Firestore db后端的应用程序,因为我不需要从应用程序中更新任何东西,而且数据是相当静态的,我想在应用程序初始化时将所有Firestore数据反序列化为Dart数据结构(理想情况下是反序列化到提供者中),以避免在我的Widget类中到处都是Future/StreamBuilder。

Firestore中的数据结构如下

代码语言:javascript
复制
Route
|->Room
   |->Point of Interest

这是Provider类

代码语言:javascript
复制
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类的摘录

代码语言:javascript
复制
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;
  }

................
}

这是主类

代码语言:javascript
复制
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中检索数据,所以与数据库的连接也是很好的。

EN

回答 1

Stack Overflow用户

发布于 2021-02-22 11:11:20

好吧,事实证明我从缓存中读取是错误的,正确的方法是(显然,如果你总是想要强制从缓存中读取)

代码语言:javascript
复制
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;
  }

这个方法尝试从缓存中读取,然后从服务器读取,所以在第一个应用程序运行时,它将从服务器读取,然后在随后的运行中,它将始终从缓存中读取,我希望这能对某些人有所帮助:)不管怎样,如果您对整个解决方案有一些观察,将非常感谢!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66309090

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档