javascript - 如何提高 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) => {
推荐阅读
- c# - 用定义长度的空格分割字符串
- spring-boot - 使用 FlywayMigrationStrategy 的多个 Flyway
- c - 关于直接访问函数返回的结构成员的警告
- arrays - Symfony Doctrine Collection 获得单一值
- c# - 解决此错误:“名称空间'System'中不存在类型或名称'Collections'。(您是否缺少程序集或引用)”?
- python - 根据某个关键字恢复python脚本
- c# - 在我的 WPF 应用程序上单击任意位置时,虚拟键盘会在 Windows 10 中弹出
- file-upload - Blazor - 无法将文件保存在文件夹 wwwroot/img 中
- php - 获取所有属于子类别的文章 ManyToMany Laravel
- kiba-etl - 如何在 Kiba 中实现本地 DB + 外部 API 源