如何提高React Native地理定位运行屏幕的性能



嗨,我目前正在尝试构建一个运行应用程序,类似于React Native中的UnderArmor运行应用程序。这些功能可以工作,但在模拟器上使用该应用程序几分钟后,计算机开始过热,应用程序的性能显著下降,过了一段时间后不再有响应。我是不是每帧计算太多了?感谢的帮助

const { width, height } = Dimensions.get('window')
const LATITUDE_DELTA = 0.007;
const LONGITUDE_DELTA = 0.007;
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324;
var email = "";
const RunMapScreen = () => {
const paperTheme = useTheme();
const [state, setState] = useState({
isActive: false,
close: true,
routeCoordinates: [],
distanceTravelled: 0,
prevLatLng: {},
latitude: LATITUDE,
longitude: LONGITUDE,
seconds: 0,
now: moment(),
then: moment(),
timeElapsed: "00:00:00",
startCounter: 0,
speedCounter: 1,
speed: 0,
averageSpeed: 0,
isModalVisible: false,
email: "grt",
});
const [isModalVisible, setModalVisible] = useState(false);
useEffect(() => {
this.watchID = navigator.geolocation.watchPosition((position) => {
handleUpdates(position, position.coords.latitude, position.coords.longitude, position.coords.speed);
});
return () => {
navigator.geolocation.clearWatch(this.watchID);
}
}, [state]);
const handleUpdates = (position, lat, long, speedVal) => {
const newLatLngs = { latitude: position.coords.latitude, longitude: position.coords.longitude }
const positionLatLngs = _.pick(position.coords, ['latitude', 'longitude']);
setState(state => ({ ...state, latitude: lat, longitude: long }));
if (state.isActive) {
setState(state => ({
...state,
routeCoordinates: state.routeCoordinates.concat(positionLatLngs),
distanceTravelled: state.distanceTravelled + calcDistance(newLatLngs),
prevLatLng: newLatLngs,
now: moment(),
timeElapsed: moment.utc(moment(state.now, "DD/MM/YYYY HH:mm:ss").diff(moment(state.then, "DD/MM/YYYY HH:mm:ss"))).format("HH:mm:ss"),
speedCounter: state.speedCounter + 1,
speed: speedVal,
averageSpeed: ((state.averageSpeed * (state.speedCounter - 1) + state.speed) / state.speedCounter),
}));
}
};
const calcDistance = (newLatLng) => {
const prevLatLng = state.prevLatLng;
return (haversine(prevLatLng, newLatLng) || 0);
};
const openIsActive = () => {
var now;
if (!state.isActive && state.startCounter === 0) {
setState(state => ({
...state,
timeElapsed: moment.duration(state.now.diff(state.then)),
then: moment(),
startCounter: 1
}));
} else if (state.isActive && state.startCounter === 1) {
now = { ...state.now };
} else if (!state.isActive && state.startCounter === 1) {
var then = { ...state.then };
var diff = -state.now.diff(now);
setState(state => ({ ...state, then: moment(then).add(diff) }));
}
setState(state => ({ ...state, isActive: !state.isActive }));
}
const saveData = () => {
firebase.auth().onAuthStateChanged((user) => {
var ref = firebase.database().ref(user.email.replace('.', ''));
var key = firebase.database().ref(ref).push().key;
firebase.database().ref(ref).child(key).set({
email: user.email,
distance: state.distanceTravelled,
time: state.timeElapsed,
speed: state.speed,
averageSpeed: state.averageSpeed
});
});
setState(state => ({
...state,
isActive: false,
routeCoordinates: [],
distanceTravelled: 0,
prevLatLng: {},
seconds: 0,
now: moment(),
then: moment(),
timeElapsed: "00:00:00",
startCounter: 0,
speedCounter: 1,
speed: 0,
averageSpeed: 0,
}));
navigator.geolocation.clearWatch(watchID);
}));
}
const endRun = () => {
if (state.isActive) {
setState(state => ({ ...state, isActive: false }));
Alert.alert(
"End Run",
"Do you want to end the run?",
[{
text: "Cancel",
onPress: () => { setState(state => ({ ...state, isActive: true })) },
style: "cancel"
},
{
text: "OK",
onPress: () => saveData()
}], { cancelable: false });
} else {
Alert.alert(
"Error",
"You cannot end run that hasn't started",
[{
text: "OK",
style: "cancel"
}], { cancelable: false });
}
}
const toggleModal = () => {
setState(state => ({ ...state, isModalVisible: !state.isModalVisible }));
};
useEffect(() => {
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 15000,
})
.then(pos => {
setState(state => ({ ...state, latitude: pos.latitude, longitude: pos.longitude }));
})
.catch(error => {
const { code, message } = error;
console.log(code, message);
});
});
const getMapRegion = () => ({
latitude: state.latitude,
longitude: state.longitude,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA
});
const { colors } = useTheme();
const theme = useTheme();
return (
<View style={styles.container}>
<Map
routeCoordinates={state.routeCoordinates}
getRegion={getMapRegion()} />
<Button title="Show modal" onPress={toggleModal} />
<Modal testID={'modal'}
isVisible={state.isModalVisible}
onSwipeComplete={() => { setModalVisible(false) }}
swipeDirection={['up', 'left', 'right', 'down']}
style={styles.modalView}>
<ModalView
timeElapsed={state.timeElapsed}
distanceTravelled={state.distanceTravelled}
speed={state.speed}
averageSpeed={state.averageSpeed}
toggleModal={toggleModal} />
</Modal>
<FloatingButton
openIsActive={openIsActive}
endRun={endRun}
toggleModal={toggleModal}
style={{ bottom: 100 }} />
</View>
);
};
export default RunMapScreen;

地图组件

const { width, height } = Dimensions.get('window')
export const Map = memo(props => {
const paperTheme = useTheme();
var mapTheme = 'standard';
if (paperTheme.dark === true) {
mapTheme = 'hybrid';
}
var backGroundColor = '#404040';
return (
<MapView
provider="google"
style={styles.map}
mapType='standard'
showsUserLocation={true}
followUserLocation={true}
region={props.getRegion}
tintColor='#404040'
overlays={[{
coordinates: props.routeCoordinates,
strokeColor: '#F02A4B',
lineWidth: 10,
}]}
>
<Polyline
coordinates={props.routeCoordinates}
strokeColor='#F02A4B'
strokeWidth={8}
/>
</MapView>
);
});

主要问题可能是在useEffect中,您开始观察位置。您使用的第二个参数是[state]。在useEffect内部,您还可以更新state。这意味着无论[state]何时更改,您的useEffect都将再次运行!这意味着无限循环,您可能在几分钟内就有数百名听众到达该位置。要解决此问题,您可能需要传递一个空数组作为第二个参数。在React hooks文档中阅读更多关于第二个参数的信息

另一个小错误:您设置了this.watchId,但在清理函数中使用了watchId。您可能想将this.watchid的行更改为:

this.watchID = navigator.geolocation.watchPosition((position) => {

最新更新