Проблема с местоположением выставки: watchPositionAsync не возвращает значение или возвращает его через долгое время (даже через 10 минут)

#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>    
  )
}
 

Я надеюсь, что это поможет, и что я понимаю проблему