Flutter 颤振Streambuilder+;Firestore在使用后台位置插件后返回空快照
添加此插件()后,我所有使用Firestore的StreamBuilder都停止工作。它为我的应用程序的所有snapshot.data返回null 情况:Flutter 颤振Streambuilder+;Firestore在使用后台位置插件后返回空快照,flutter,background-process,stream-builder,Flutter,Background Process,Stream Builder,添加此插件()后,我所有使用Firestore的StreamBuilder都停止工作。它为我的应用程序的所有snapshot.data返回null 情况: StreamBuilder适用于应用程序上Firestore的所有集合 使用carp\u background\u location就像在特定屏幕上的example/lib/main.dart一样 应用程序上的snapshot.data上的所有流都返回null 当我关闭应用程序并再次运行main.dart(并且不运行后台位置)时,正常行为就会
carp\u background\u location
就像在特定屏幕上的example/lib/main.dart
一样import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:provider/provider.dart';
import 'begin_activity.dart';
class MainApp extends StatefulWidget {
@override
_MainAppState createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
final _firestore = FirebaseFirestore.instance;
@override
Widget build(BuildContext context) {
void moveToPage() async {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => LocationStreamWidget()),
);
}
return Scaffold(
backgroundColor: Colors.grey,
floatingActionButton: FloatingActionButton(
mini: true,
onPressed: () {
moveToPage();
},
child: Icon(
Icons.add,
color: Colors.white,
size: 30,
),
backgroundColor: Colors.blue,
),
body: Stack(
children: [
Padding(
padding: EdgeInsets.fromLTRB(10, 0, 10, 10),
child: StreamBuilder(
stream: _firestore
.collection('users')
.doc('user_id')
.collection('corridas')
.orderBy('date', descending: true)
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.data == null) {
return Center(
child: SpinKitCubeGrid(
size: 51.0, color: Colors.blue,));
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (snapshot.data.docs.isEmpty) {
return Container(
height: MediaQuery.of(context).size.height * 0.55,
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 50.0, 8.0, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.directions_run,
size: 50,
),
Text(
Strings.noTracks,
style: TextParameters.noActivities,
textAlign: TextAlign.center,
),
],
),
));
} else if (snapshot.hasData) {
return Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
final docAux = snapshot.data.docs;
return Container(
child: Column(
children: [
Text(_printDate(docAux[index]['date'])
.toString()),
Text(
docAux[index]['distance'].toStringAsFixed(2),
),
],
));
},
),
),
],
);
} else {
return Center(
child: SpinKitCubeGrid(
size: 51.0, color: Colors.blue,));
}
},
),
),
],
),
);
}
}
String _printTime(int timeInMilliseconds) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
Duration duration = Duration(milliseconds: timeInMilliseconds);
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
if (duration.inHours > 0)
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
else
return "$twoDigitMinutes:$twoDigitSeconds";
}
String _printDate(Timestamp timestamp) {
var formattedAux = timestamp.toDate();
var day = formattedAux.day.toString().padLeft(2, '0');
var month = formattedAux.month.toString().padLeft(2, '0');
var year = formattedAux.year;
return '$year' + '-' + '$month' + '-' + '$day';
}
import'包:cloud_firestore/cloud_firestore.dart';
进口“包装:颤振/cupertino.dart”;
进口“包装:颤振/材料.省道”;
导入“package:flatter/rendering.dart”;
进口“包装:颤振旋转套件/颤振旋转套件.dart”;
导入“包:provider/provider.dart”;
导入“begin_activity.dart”;
类MainApp扩展StatefulWidget{
@凌驾
_MainAppState createState()=>\u MainAppState();
}
类_MainAppState扩展状态{
final _firestore=FirebaseFirestore.instance;
@凌驾
小部件构建(构建上下文){
void moveToPage()异步{
等待导航器(
上下文
MaterialPage路由(生成器:(上下文)=>LocationStreamWidget()),
);
}
返回脚手架(
背景颜色:颜色。灰色,
浮动操作按钮:浮动操作按钮(
米尼:是的,
已按下:(){
moveToPage();
},
子:图标(
Icons.add,
颜色:颜色,白色,
尺码:30,
),
背景颜色:Colors.blue,
),
主体:堆栈(
儿童:[
填充物(
填充:从LTRB(10,0,10,10)开始的边缘设置,
孩子:StreamBuilder(
流:_firestore
.collection('用户')
.doc('user\u id')
.collection(“corridas”)
.orderBy('date',降序:true)
.snapshots(),
生成器:(BuildContext上下文,
异步快照(快照){
如果(snapshot.data==null){
返回中心(
孩子:SpinKitCubeGrid(
尺寸:51.0,颜色:彩色。蓝色,);
}else if(snapshot.hasrerror){
返回中心(子项:Text('Error:${snapshot.Error}');
}else if(snapshot.data.docs.isEmpty){
返回容器(
高度:MediaQuery.of(上下文).size.height*0.55,
孩子:填充(
填充:LTRB(8.0,50.0,8.0,0)中的常数边集,
子:列(
mainAxisAlignment:mainAxisAlignment.center,
crossAxisAlignment:crossAxisAlignment.center,
儿童:[
图标(
Icons.directions\u run,
尺码:50,
),
正文(
字符串。noTracks,
样式:TextParameters.noActivities,
textAlign:textAlign.center,
),
],
),
));
}else if(snapshot.hasData){
返回列(
儿童:[
扩大(
子项:ListView.builder(
itemCount:snapshot.data.docs.length,
itemBuilder:(上下文,索引){
最终文档=snapshot.data.docs;
返回容器(
子:列(
儿童:[
文本(_printDate(docAux[index]['date']))
.toString()),
正文(
docAux[索引][距离].toStringAsFixed(2),
),
],
));
},
),
),
],
);
}否则{
返回中心(
孩子:SpinKitCubeGrid(
尺寸:51.0,颜色:彩色。蓝色,);
}
},
),
),
],
),
);
}
}
字符串_printTime(int timein毫秒){
字符串两位数(整数n){
如果(n>=10)返回“$n”;
返回“0$n”;
}
Duration Duration=持续时间(毫秒:TimeinMillions);
字符串twoDigitMinutes=twoDigits(持续时间.inMinutes.余数(60));
字符串twoDigitSeconds=twoDigits(duration.unseconds.rements(60));
如果(持续时间>0)
返回“${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds”;
其他的
返回“$twoDigitMinutes:$twoDigitSeconds”;
}
字符串_printDate(时间戳){
var formattedAux=timestamp.toDate();
var day=formattedAux.day.toString().padLeft(2,'0');
var month=formattedAux.month.toString().padLeft(2,'0');
var year=formattedAux.year;
返回'$year'+'-'+'$mont
import 'dart:async';
import 'package:carp_background_location/carp_background_location.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:provider/provider.dart';
import 'package:timer_builder/timer_builder.dart';
class LocationStreamWidget extends StatefulWidget {
@override
State<LocationStreamWidget> createState() => LocationStreamState();
}
enum LocationStatus { UNKNOWN, RUNNING, STOPPED }
class LocationStreamState extends State<LocationStreamWidget> {
final globalKey = GlobalKey<ScaffoldState>();
LocationManager locationManager = LocationManager.instance;
Stream<LocationDto> dtoStream;
StreamSubscription<LocationDto> dtoSubscription;
LocationStatus _status = LocationStatus.UNKNOWN;
// Definitions
List<LocationDto> _allPositions;
List<LocationDto> _positions = <LocationDto>[];
double totalDistance;
double intermediaryDist;
double distAux;
double distLatLong;
int totalTime;
int intermediaryTime;
int timeAux;
List<LocationDto> _allPositionsInter;
List<LocationDto> _positionsInter = <LocationDto>[];
final _firestore = FirebaseFirestore.instance;
@override
void initState() {
super.initState();
locationManager.interval = 1;
locationManager.distanceFilter = 0;
dtoStream = locationManager.dtoStream;
totalDistance = 0.0;
intermediaryDist = 0.0;
totalTime = 0;
intermediaryTime = 0;
_positions.clear();
}
void onData(LocationDto dto) {
setState(() {
if (_status == LocationStatus.UNKNOWN) {
_status = LocationStatus.RUNNING;
}
_positions.add(dto);
_allPositions = _positions;
print(_positions.length);
_positionsInter.add(dto);
_allPositionsInter = _positionsInter;
final firstTime = DateTime.fromMillisecondsSinceEpoch(
_allPositionsInter.first.time ~/ 1)
.toLocal();
final lastTime =
DateTime.fromMillisecondsSinceEpoch(_allPositionsInter.last.time ~/ 1)
.toLocal();
totalTime =
intermediaryTime + lastTime.difference(firstTime).inMilliseconds;
print(totalTime);
});
}
void start() async {
if (dtoSubscription != null) {
dtoSubscription.resume();
}
dtoSubscription = dtoStream.listen(onData);
await locationManager.start();
setState(() {
_status = LocationStatus.RUNNING;
});
}
void pause() async {
setState(() {
intermediaryDist = totalDistance;
intermediaryTime = totalTime;
_positionsInter.clear();
_allPositionsInter.clear();
_status = LocationStatus.STOPPED;
});
dtoSubscription.cancel();
await locationManager.stop();
}
String _printTime(int timeInMilliseconds) {
String twoDigits(int n) {
if (n >= 10) return "$n";
return "0$n";
}
Duration duration = Duration(milliseconds: timeInMilliseconds);
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
if (duration.inHours > 0)
return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
else
return "$twoDigitMinutes:$twoDigitSeconds";
}
@override
void dispose() {
if (dtoSubscription != null) {
dtoSubscription.cancel();
dtoSubscription = null;
_allPositions.clear();
_allPositionsInter.clear();
totalDistance = 0;
intermediaryDist = 0.0;
distAux = 0.0;
_status = LocationStatus.STOPPED;
totalTime = 0;
intermediaryTime = 0;
locationManager.start();
if (_positions != null) {
_positions.clear();
_positionsInter.clear();
_allPositionsInter.clear();
locationManager.start();
}
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return TimerBuilder.periodic(Duration(milliseconds: 500),
builder: (context) {
return Scaffold(
key: globalKey,
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Container(
child: FutureBuilder(
future: locationManager.checkIfPermissionGranted(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.data == false) {
return Text('No gps');
}
return Container(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'${totalTime != null ? _printTime(totalTime) : '0'}',
),
_getButtons(user),
],
),
),
);
}),
),
),
],
),
);
});
}
Widget _getButtons(UserClasse user) {
final _currentDate = _positions?.isNotEmpty ?? false
? (DateTime.fromMillisecondsSinceEpoch(_positions[0].time ~/ 1)
.toLocal())
: 0;
if (dtoSubscription == null)
return Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
child: Text('Begin'),
color: Colors.blue,
onPressed: start),
),
],
),
);
else if (_status == LocationStatus.RUNNING)
return Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
child: Text('Pause'),
color: Colors.blue,
onPressed: pause),
),
],
),
);
else if (_status == LocationStatus.STOPPED) {
return Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
child: Text('Back'),
color: Colors.blue,
onPressed: start),
),
SizedBox(
width: 15,
),
Expanded(
child: RaisedButton(
child: Text('Stop'),
color: Colors.blue,
onPressed: () {},
onLongPress: () async {
_firestore
.collection('users')
.doc('user_id')
.collection('corridas')
.add({
'date': _currentDate,
'distance': 41.7,
'pace': 1244,
'average_speed': 12,
'runtime': 14134,
'max_speed': 41,
'max_altitude': 13,
'delta_altitude': 13,
'lat_first': -23.213,
'long_first': -23.213,
'polylines': 'feaf',
'markers': [1, 2, 3],
});
Navigator.of(context).pop();
},
),
),
],
),
);
} else
return Padding(
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
child: Text('Start'),
color: Colors.blue,
onPressed: () {}),
),
],
),
);
}
}