Снимок флаттера Streambuilder не содержит данных после выполнения условия - PullRequest
2 голосов
/ 11 января 2020

У меня есть класс Home с PageView в качестве тела и BottomNavigationBar. В этом классе загружается текущий пользователь и текущее местоположение пользователя. Когда пользователь и местоположение известны, глобальной переменной присваивается значение true

. На первом значке вкладки BottomNavigationBar есть лента ближайших местоположений, закодированных в классе Feed

Сейчас проблема. Когда я запускаю приложение в первый раз или делаю горячую перезагрузку geoQuery() возвращает круговой счетчик. Когда текущий пользователь загружен, он возвращает текст «Нет данных» вместо отображения событий. Пользователь должен изменить вкладку BottomNavigationBar с ленты на что-то другое и обратно на ленту, чтобы обновить sh построитель потоков. После этого он работает как положено.

Когда я использую Streambuilder без условия (currentLocationloaded && currentUserloaded == true), он работает как положено, но иногда выдает ошибку, поскольку пользователь загружается недостаточно быстро.

Что можно сделать, чтобы заставить его работать с условием?

Обновление

Рабочий процесс зарегистрирован : RootPage -> Logged в? -> Home

RootPage

enum AuthStatus {
  NOT_DETERMINED,
  NOT_LOGGED_IN,
  LOGGED_IN,
}

class RootPage extends StatefulWidget {
  RootPage({this.auth});

  final BaseAuth auth;

  @override
  State<StatefulWidget> createState() => new _RootPageState();
}

class _RootPageState extends State<RootPage> {
  AuthStatus authStatus = AuthStatus.NOT_DETERMINED;
  String _userID = "";

  @override
  void initState() {
    super.initState();
    widget.auth.getCurrentUser().then((user) {
      setState(() {
        if (user != null) {
          _userID = user?.uid;
        }
        authStatus =
            user?.uid == null ? AuthStatus.NOT_LOGGED_IN : AuthStatus.LOGGED_IN;
      });
    });
  }

  void loginCallback() {
    widget.auth.getCurrentUser().then((user) {
      setState(() {
        _userID = user.uid.toString();
      });
    });
    setState(() {
      authStatus = AuthStatus.LOGGED_IN;
    });
  }

  void logoutCallback() {
    setState(() {
      authStatus = AuthStatus.NOT_LOGGED_IN;
      _userID = "";
    });
  }

  Widget buildWaitingScreen() {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: CircularProgressIndicator(),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    switch (authStatus) {
      case AuthStatus.NOT_DETERMINED:
        return buildWaitingScreen();
        break;
      case AuthStatus.NOT_LOGGED_IN:
        return new StartPage(
          auth: widget.auth,
          loginCallback: loginCallback,
        );
        break;
      case AuthStatus.LOGGED_IN:
        if (_userID.length > 0 && _userID != null) {
          return new Home(
            userID: _userID,
            auth: widget.auth,
            logoutCallback: logoutCallback,
          );
        } else
          return buildWaitingScreen();
        break;
      default:
        return buildWaitingScreen();
    }
  }
}

Home

User currentUser;
bool currentUserloaded = false;
bool currentLocationloaded = false;

class Home extends StatefulWidget {
  final BaseAuth auth;
  final VoidCallback logoutCallback;
  final String userID;

  const Home({Key key, this.auth, this.logoutCallback, this.userID})
      : super(key: key);

  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  PageController pageController;
  int pageIndex = 0;
  double longitude;
  double latitude;

  //INIT
  @override
  void initState() {
    super.initState();
    loadCurrentUser();
    getCurrentLocation();
    pageController = PageController();
  }


  //LOAD current user
  loadCurrentUser() async {
    print("Current User ${widget.userID}");
    DocumentSnapshot doc = await userRef.document(widget.userID).get();
    currentUser = User.fromDocument(doc);
    setState(() {
      currentUserloaded = true;
      print("User loaded $currentUserloaded");
    });
  }

  //get current location
  getCurrentLocation() async {
    var currentLocationCoordinates = await Geolocator()
        .getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    List<Placemark> place = await Geolocator().placemarkFromCoordinates(
        currentLocationCoordinates.latitude,
        currentLocationCoordinates.longitude);
    latitude = currentLocationCoordinates.latitude;
    longitude = currentLocationCoordinates.longitude;
    setState(() {
      currentLocationloaded = true;
      print("Got location $currentLocationloaded");
    });
  }

  //DISPOSE
  @override
  void dispose() {
    pageController.dispose();
    super.dispose();
  }

  //Pageview
  onPageChanged(int pageIndex) {
    setState(() {
      this.pageIndex = pageIndex;
    });
  }

  //On Tap of ButtomTabbar => Jump to next Page
  onTap(int pageIndex) {
    if (currentUserloaded && currentLocationloaded) {
      pageController.jumpToPage(pageIndex);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      body: PageView(
        children: <Widget>[
          Feed(userID: widget.userID, latitude: latitude, longitude: longitude),
          SearchView(),
          ChatHome(),
          Profile(
              uid: currentUser?.uid,
              auth: widget.auth,
              logoutCallback: widget.logoutCallback),
        ],
        controller: pageController,
        onPageChanged: onPageChanged,
        physics: NeverScrollableScrollPhysics(),
      ),
      bottomNavigationBar: CupertinoTabBar(
          currentIndex: pageIndex,
          inactiveColor: Colors.white,
          backgroundColor: Colors.blue,
          activeColor: Colors.orange,
          onTap: onTap,
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home, size: 20),
              title: Text("Home"),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.search, size: 20),
              title: Text("Search"),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.chat, size: 20),
              title: Text("chat"),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.profil, size: 20),
              title: Text("Profil"),
            ),
          ]),
    );
  }
}

Feed

class Feed extends StatefulWidget {
  final String userID;
  final double latitude;
  final double longitude;

  const Feed({Key key, this.userID, this.latitude, this.longitude})
      : super(key: key);

  @override
  _FeedState createState() => _FeedState();
}

class _FeedState extends State<Feed> {
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  List<Event> events = [];

  var radius = BehaviorSubject<double>.seeded(50.0);
  Stream<List<DocumentSnapshot>> stream;
  Geoflutterfire geo;

  @override
  void initState() {
    super.initState();
    geo = Geoflutterfire();
    GeoFirePoint center = geo.point(
        latitude: widget.latitude,
        longitude: widget
            .longitude); 
    stream = radius.switchMap((rad) {
      var collectionReference =
          eventRef.where("event", isEqualTo: "festival");
      return geo.collection(collectionRef: collectionReference).within(
          center: center, radius: rad, field: 'position', strictMode: true);
    });
  }

  //GEOQUERY

  Widget geoQuery() {
    if (currentLocationloaded && currentUserloaded) {
      return Column(
        children: <Widget>[
          StreamBuilder(
            stream: stream,
            builder: (BuildContext context,
                AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
              if (!snapshot.hasData) {
                Text("No data");
              }
              events =
                  snapshot.data.map((doc) => Event.fromDocument(doc)).toList();
              events.sort((a, b) {
                var aDate = a.timestamp;
                var bDate = b.timestamp;
                return aDate.compareTo(bDate);
              });
              if (events.isEmpty) {
                return Text("No events");
              }
              return Flexible(
                child: ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) {
                    return buildEvent(index);
                  },
                ),
              );
            },
          )
        ],
      );
    } else {
      return circularProgress();
    }
  }


  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          centerTitle: true,
          title: Text("Feed"),
          backgroundColor: Colors.blue,
        ),
        body: geoQuery(),
        );
  }
}

Обновление 2

Если я использую жестко заданную широту и долготу для GeoFirePoint center = geo.point(latitude: 37.773972, longitude: -122.431297);, это работает! Похоже, проблема с передачей текущего местоположения пользователя. Есть предложения?

1 Ответ

1 голос
/ 12 января 2020

Проблема заключалась в том, что местоположение текущего пользователя не было передано вовремя. Просто установите

GeoFirePoint center = geo.point(
        latitude: widget.latitude,
        longitude: widget
            .longitude); 
    stream = radius.switchMap((rad) {
      var collectionReference =
          eventRef.where("event", isEqualTo: "festival");
      return geo.collection(collectionRef: collectionReference).within(
          center: center, radius: rad, field: 'position', strictMode: true);
    });

из initState в geoQuery()

...