#react-native #geolocation #location #expo
Вопрос:
Добрый вечер, я разрабатываю свое первое приложение React Native Expo для хобби. Это приложение, которое использует геолокацию мобильного телефона для отслеживания перемещений пользователей, чтобы организовать охоту за сокровищами в городе. Но у меня возникла проблема: функция watchPositionAsync работает очень беспорядочно. Иногда значение объекта местоположения возвращается сразу же. Однако в большинстве случаев он вообще не возвращается или даже занимает 10 минут, чтобы сделать это.
Это первая версия кода, содержащая только рассматриваемую функцию:
import React, {useState, useEffect} from 'react';
import * as Location from 'expo-location';
const Navigator = () => {
const [deviceLocation, setDeviceLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState(null);
const getLocationAsync = async() => {
let loc = await Location.watchPositionAsync({
accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 10000,
distanceInterval : 20
},
(newLocation) => {
setDeviceLocation(newLocation);
}
);
};
getLocationAsync()
useEffect(() => {
(async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
return;
}
})();
}, []);
let text = 'Waiting..';
if (errorMsg) {
text = errorMsg;
} else if (deviceLocation.location !== '') {
text = JSON.stringify(deviceLocation.location);
}
return (
<View>
<Text>{text}</Text>
</View>
)
}
Это версия с дополнительными функциями (такими как вычисление расстояния от заданной точки при каждом повторном отображении функции watchPositionAsync и установка конкретного предложения, которое будет сообщено пользователю).:
import React, {useState, useEffect} from 'react';
import NavigatorUI from './NavigatorUI';
import * as Location from 'expo-location';
import { getDistance, findNearest } from 'geolib';
const treasureLocation = {
latitude: 39.2695552,
longitude: 8.4679172
}
const Navigator = () => {
const [deviceLocation, setDeviceLocation] = useState({
location : '',
treasureDist : '',
sentence: ''
});
const [errorMsg, setErrorMsg] = useState(null);
const getLocationAsync = async() => {
let loc = await Location.watchPositionAsync({
accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 10000,
distanceInterval : 20
},
(newLocation) => {
setDeviceLocation({...deviceLocation, location: newLocation});
getDistfromTreasure();
switchDist();
console.warn(deviceLocation.sentence)
}
);
};
getLocationAsync()
const getDistfromTreasure = () => {
if(deviceLocation.location){
let {latitude: deviceLat, longitude: deviceLong} = deviceLocation.location.coords;
let {latitude: treasureLat, longitude: treasureLong} = treasureLocation;
let dist = getDistance({
latitude: deviceLat,
longitude: deviceLong
},
{
latitude: treasureLat,
longitude: treasureLong
}
);
setDeviceLocation({...deviceLocation, treasureDist: dist})
}
};
const switchDist = () =>{
if(deviceLocation.treasureDist){
let {treasureDist: val} = deviceLocation;
if(val > 1000){
setDeviceLocation({...deviceLocation, sentence: 'Example1'});
}
else if(val < 1000 amp;amp; val > 500){
setDeviceLocation({...deviceLocation, sentence: 'Example2'});
}
else if(val < 500 amp;amp; val > 100){
setDeviceLocation({...deviceLocation, sentence: 'Example3'});
}
else if(val < 100 amp;amp; val > 50){
setDeviceLocation({...deviceLocation, sentence: 'Example4'});
}
else if(val < 50){
setDeviceLocation({...deviceLocation, sentence: 'Example5'});
}
}
}
useEffect(() => {
(async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
return;
}
})();
}, []);
let text = 'Waiting..';
if (errorMsg) {
text = errorMsg;
} else if (deviceLocation.location !== '') {
text = JSON.stringify(deviceLocation.location);
}
return (
<>
<View>
<Text>{text}</Text>
</View>
<View>
<Text>{sentence}</Text>
</View>
</>
)
}
export default Navigator
В обоих случаях на экране остается слово «Ожидание» в течение бесконечного времени.
Кроме того, во втором случае я заметил, что повторная визуализация происходит намного быстрее или намного медленнее, чем я установил с помощью параметра timeInterval. В любом случае с прерывистой скоростью.
У кого-нибудь была такая же проблема, и ему удалось ее решить?
Ответ №1:
код кажется мне почти нормальным. Я думаю, что в первом коде, который вы опубликовали, есть ошибка в последнем, если перед рендерингом. Объект местоположения, заданный expo, содержит координаты свойств, и вам нужно проверить, определено ли местоположение устройства, прежде чем читать это.
else if (deviceLocation.location !== '') {
text = JSON.stringify(deviceLocation.location);}
->
else if (deviceLocation amp;amp; deviceLocation.coords) {
text = JSON.stringify(deviceLocation.coords)};
Я также немного поиграл с этим кодом и написал бы его так:
const Navigator = () => {
console.log('render')
const [permissionResult, setPermissionResult] = useState(undefined);
const [deviceLocation, setDeviceLocation] = useState(null);
const [errorMsg, setErrorMsg] = useState(null);
const getPermissionAsync = async () => {
let { status } = await Location.requestForegroundPermissionsAsync();
setPermissionResult(status)
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied');
return;
}
}
const getLocationAsync = async() => {
await Location.watchPositionAsync({
accuracy: Location.Accuracy.BestForNavigation,
timeInterval: 10000,
distanceInterval : 20
},
(newLocation) => {
setDeviceLocation(newLocation);
}
);
};
useEffect(() => {
// If permission request is not done
if (permissionResult === undefined) {
getPermissionAsync();
}
}, [permissionResult]);
useEffect(()=>{
// If permission has been done and the result is available
if (permissionResult !== undefined) {
getLocationAsync()
}
}, [permissionResult])
let text = 'Waiting..';
if (errorMsg) {
console.log('errore')
text = errorMsg;
} else if (deviceLocation amp;amp; deviceLocation.coords) {
text = JSON.stringify(deviceLocation.coords);
console.log(deviceLocation)
}
return (
<View>
<Text>{text}</Text>
</View>
)
}
Я надеюсь, что это поможет, и что я понимаю проблему